` pour que votre application fournisse les valeurs finales et indique au fusionneur de manifeste de remplacer les valeurs des bibliothèques :
```xml
...
```
Si un SDK définit également `android:allowBackup`, incluez-le dans `tools:replace` :
```xml
tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules"
```
#### 3. Créez des fichiers de règles de sauvegarde fusionnées
Créez des fichiers XML dans `app/src/main/res/xml/` qui combinent les règles d'Adapty avec celles des autres SDKs. Android utilise différents formats de règles de sauvegarde selon la version du système, donc créer les deux fichiers garantit la compatibilité avec toutes les versions Android que votre application prend en charge.
:::note
Les exemples ci-dessous utilisent AppsFlyer comme SDK tiers d'exemple. Remplacez ou ajoutez des règles pour tout autre SDK que vous utilisez dans votre application.
:::
**Pour Android 12 et supérieur** (utilise le nouveau format de règles d'extraction de données) :
```xml title="sample_data_extraction_rules.xml"
```
**Pour Android 11 et inférieur** (utilise l'ancien format de contenu de sauvegarde complète) :
```xml title="sample_backup_rules.xml"
```
Avec cette configuration :
- Les exclusions de sauvegarde d'Adapty (`AdaptySDKPrefs.xml`) sont préservées.
- Les exclusions des autres SDKs (par exemple, `appsflyer-data`) sont également appliquées.
- Le fusionneur de manifeste utilise la configuration de votre application et n'échoue plus sur les attributs de sauvegarde conflictuels.
#### Les achats échouent après le retour depuis une autre application
Si l'Activity qui démarre le flux d'achat utilise un `launchMode` non standard, Android peut la recréer ou la réutiliser de manière incorrecte lorsque l'utilisateur revient depuis Google Play, une application bancaire ou un navigateur. Cela peut entraîner la perte du résultat de l'achat ou son traitement comme annulé.
Pour que les achats fonctionnent correctement, utilisez uniquement les modes de lancement `standard` ou `singleTop` pour l'Activity qui démarre le flux d'achat, et évitez tout autre mode.
Dans votre `AndroidManifest.xml`, vérifiez que l'Activity qui démarre le flux d'achat est définie sur `standard` ou `singleTop` :
```xml
```
---
# File: android-quickstart-paywalls
---
---
title: "Activer les achats avec Flow Builder dans le SDK Android"
description: "Guide de démarrage rapide pour activer les achats intégrés avec Adapty Flow Builder."
---
Pour activer les achats intégrés, vous devez comprendre trois concepts clés :
- [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie)
- [**Flows**](adapty-flow-builder) – séquences d'écrans qui présentent des produits aux utilisateurs, créées dans le Flow Builder sans code. Le SDK les récupère via `getFlow`. Si vous préférez construire l'interface dans votre propre code, utilisez un paywall à la place — voir [Implémenter les paywalls manuellement](android-quickstart-manual).
- [**Placements**](placements) – où et quand vous affichez les flows dans votre app (comme `main`, `onboarding`, `settings`). Vous associez les flows aux placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite l'exécution de tests A/B et l'affichage de flows différents selon les utilisateurs.
Adapty vous propose trois façons d'activer les achats dans votre app. Choisissez celle qui correspond à vos besoins :
| Implémentation | Complexité | Quand l'utiliser |
|---|---|---|
| Adapty Flow Builder | ✅ Facile | Vous [créez un flow complet et prêt à l'achat dans le builder sans code](quickstart-paywalls). Adapty le rend automatiquement et gère l'intégralité du flow d'achat, la validation des reçus et la gestion des abonnements en coulisses. |
| Paywalls créés manuellement | 🟡 Moyen | Vous implémentez l'interface de votre paywall dans le code de votre app, mais obtenez tout de même l'objet flow depuis Adapty pour conserver la flexibilité des offres de produits. Voir le [guide](android-quickstart-manual). |
| Mode observateur | 🔴 Difficile | Vous disposez déjà de votre propre infrastructure de gestion des achats et souhaitez continuer à l'utiliser. Notez que le mode observateur a ses limites dans Adapty. Voir l'[article](observer-vs-full-mode). |
:::important
**Les étapes ci-dessous montrent comment implémenter un flow créé dans Adapty Flow Builder.**
Si vous préférez construire l'interface du paywall vous-même, consultez [Implémenter les paywalls manuellement](android-quickstart-manual).
:::
Pour afficher un flow créé dans Adapty Flow Builder, vous avez uniquement besoin, dans le code de votre app, de :
1. **Obtenir le flow** : Récupérez-le depuis Adapty.
2. **L'afficher et laisser Adapty gérer les achats** : Affichez la vue dans votre app.
3. **Gérer les actions des boutons** : Associez les interactions utilisateur aux réponses de votre app. Par exemple, ouvrir des liens ou fermer le flow lorsque les utilisateurs cliquent sur des boutons.
## Avant de commencer \{#before-you-start\}
Avant de commencer, effectuez ces étapes :
1. [Connectez votre app à Google Play](initial-android) dans l'Adapty Dashboard.
2. [Créez vos produits](create-product) dans Adapty.
3. [Créez un flow et ajoutez-y des produits](create-paywall).
4. [Créez un placement et ajoutez-y votre flow](create-placement).
5. [Installez et activez le SDK Adapty](sdk-installation-android) dans le code de votre app. Ce guide utilise les API du SDK Adapty Android v4.
:::tip
La façon la plus rapide d'effectuer ces étapes est de suivre le [guide de démarrage rapide](quickstart) ou de créer des flows et des placements avec la [CLI développeur](developer-cli-quickstart).
:::
## 1. Obtenir le flow \{#1-get-the-flow\}
Vos flows sont associés aux placements configurés dans le tableau de bord. Les placements vous permettent d'exécuter différents flows pour différentes audiences ou de lancer des [tests A/B](ab-tests).
Pour obtenir un flow créé dans Adapty Flow Builder, vous devez :
1. Obtenir l'objet `flow` par l'ID du [placement](placements) en utilisant la méthode `getFlow` et vérifier s'il dispose d'une configuration de vue.
2. Obtenir la configuration de vue à l'aide de la méthode `getFlowConfiguration`. La configuration de vue contient les éléments d'interface et le style nécessaires pour afficher le flow.
:::important
Pour obtenir la configuration de vue, vous devez activer le bouton **Show on device** dans le Flow Builder. Sinon, vous obtiendrez une configuration de vue vide et le flow ne sera pas affiché.
:::
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
if (result is AdaptyResult.Success) {
val flow = result.value
if (!flow.hasViewConfiguration) {
return@getFlow
}
AdaptyUI.getFlowConfiguration(flow) { configResult ->
if (configResult is AdaptyResult.Success) {
val flowConfiguration = configResult.value
}
}
}
}
```
```java showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
if (!flow.hasViewConfiguration()) {
return;
}
AdaptyUI.getFlowConfiguration(flow, configResult -> {
if (configResult instanceof AdaptyResult.Success) {
AdaptyUI.FlowConfiguration flowConfiguration =
((AdaptyResult.Success) configResult).getValue();
// use loaded configuration
}
});
}
});
```
## 2. Afficher le flow \{#2-display-the-flow\}
Maintenant que vous avez la configuration du flow, quelques lignes suffisent pour l'afficher.
Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement l'`AdaptyFlowView` :
```kotlin showLineNumbers
val flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
null, // products = null means auto-fetch
eventListener,
)
```
```kotlin showLineNumbers
val flowView =
AdaptyFlowView(activity) // or retrieve it from xml
...
with(flowView) {
showFlow(
flowConfiguration,
null, // products = null means auto-fetch
eventListener,
)
}
```
```java showLineNumbers
AdaptyFlowView flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
null, // products = null means auto-fetch
eventListener
);
```
```java showLineNumbers
AdaptyFlowView flowView =
new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
flowView.showFlow(flowConfiguration, products, eventListener);
```
```xml showLineNumbers
```
Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil.
:::tip
Pour plus de détails sur l'affichage d'un flow, consultez notre [guide](android-present-paywalls).
:::
## 3. Gérer les actions des boutons \{#3-handle-button-actions\}
Lorsque les utilisateurs cliquent sur des boutons dans le flow, le SDK Android gère automatiquement les achats, la restauration, la fermeture du flow et l'ouverture des liens.
Cependant, d'autres boutons ont des ID personnalisés ou prédéfinis et nécessitent une gestion des actions dans votre code. Ou vous pouvez souhaiter remplacer leur comportement par défaut.
Par exemple, voici le comportement par défaut du bouton de fermeture. Vous n'avez pas besoin de l'ajouter dans le code, mais vous pouvez voir ici comment procéder si nécessaire.
:::tip
Consultez nos guides sur la gestion des [actions](android-handle-paywall-actions) et des [événements](android-handling-events) des boutons.
:::
```kotlin showLineNumbers title="Kotlin"
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior
}
}
```
```java showLineNumbers
@Override
public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) {
if (action instanceof AdaptyUI.Action.Close) {
if (context instanceof Activity) {
((Activity) context).onBackPressed();
}
}
}
```
## Étapes suivantes \{#next-steps\}
:::tip
Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider !
:::
Votre flow est prêt à être affiché dans l'app. [Testez vos achats dans le Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le flow.
Vous devez ensuite [vérifier le niveau d'accès des utilisateurs](android-check-subscription-status) pour vous assurer d'afficher un flow ou de donner accès aux fonctionnalités payantes aux bons utilisateurs.
## Exemple complet \{#full-example\}
Voici comment toutes ces étapes peuvent être intégrées ensemble dans votre app.
```kotlin showLineNumbers title="Kotlin"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Adapty.getFlow("YOUR_PLACEMENT_ID") { flowResult ->
if (flowResult is AdaptyResult.Success) {
val flow = flowResult.value
if (!flow.hasViewConfiguration) {
// Use custom logic
return@getFlow
}
AdaptyUI.getFlowConfiguration(flow) { configResult ->
if (configResult is AdaptyResult.Success) {
val flowConfiguration = configResult.value
val flowView = AdaptyUI.getFlowView(
this,
flowConfiguration,
null, // products = null means auto-fetch
object : AdaptyFlowDefaultEventListener() {
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
is AdaptyUI.Action.Close -> {
(context as? Activity)?.onBackPressed()
}
}
}
}
)
setContentView(flowView)
}
}
}
}
}
}
```
```java showLineNumbers
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Adapty.getFlow("YOUR_PLACEMENT_ID", flowResult -> {
if (flowResult instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) flowResult).getValue();
if (!flow.hasViewConfiguration()) {
// Use custom logic
return;
}
AdaptyUI.getFlowConfiguration(flow, configResult -> {
if (configResult instanceof AdaptyResult.Success) {
AdaptyUI.FlowConfiguration flowConfiguration =
((AdaptyResult.Success) configResult).getValue();
AdaptyFlowView flowView = AdaptyUI.getFlowView(
this,
flowConfiguration,
null, // products = null means auto-fetch
new AdaptyFlowDefaultEventListener() {
@Override
public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) {
if (action instanceof AdaptyUI.Action.Close) {
if (context instanceof Activity) {
((Activity) context).onBackPressed();
}
}
}
}
);
setContentView(flowView);
}
});
}
});
}
}
```
---
# File: android-check-subscription-status
---
---
title: "Vérifier le statut d'abonnement dans le SDK Android"
description: "Apprenez à vérifier le statut d'abonnement dans votre application Android avec Adapty."
---
Pour décider si les utilisateurs peuvent accéder au contenu payant ou voir un paywall, vous devez vérifier leur [niveau d'accès](access-level) dans le profil.
Cet article vous montre comment accéder à l'état du profil pour décider ce que les utilisateurs doivent voir — afficher un paywall ou leur donner accès aux fonctionnalités payantes.
## Obtenir le statut d'abonnement \{#get-subscription-status\}
Lorsque vous décidez d'afficher un paywall ou du contenu payant à un utilisateur, vous vérifiez son [niveau d'accès](access-level) dans son profil. Deux options s'offrent à vous :
- Appelez `getProfile` si vous avez besoin des dernières données de profil immédiatement (par exemple au lancement de l'application) ou pour forcer une mise à jour.
- Configurez les **mises à jour automatiques du profil** pour conserver une copie locale qui se rafraîchit automatiquement dès que le statut d'abonnement change.
### Obtenir le profil \{#get-profile\}
La façon la plus simple d'obtenir le statut d'abonnement est d'utiliser la méthode `getProfile` pour accéder au profil :
```kotlin showLineNumbers
Adapty.getProfile { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
// check the access
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getProfile(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
// check the access
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
### Écouter les mises à jour d'abonnement \{#listen-to-subscription-updates\}
Pour recevoir automatiquement les mises à jour du profil dans votre application :
1. Utilisez `Adapty.setOnProfileUpdatedListener()` pour écouter les changements de profil — Adapty appellera automatiquement cette méthode dès que le statut d'abonnement de l'utilisateur change.
2. Stockez les données de profil mises à jour lorsque cette méthode est appelée, afin de pouvoir les utiliser partout dans votre application sans effectuer de requêtes réseau supplémentaires.
```kotlin
class SubscriptionManager {
private var currentProfile: AdaptyProfile? = null
init {
// Listen for profile updates
Adapty.setOnProfileUpdatedListener { profile ->
currentProfile = profile
// Update UI, unlock content, etc.
}
}
// Use stored profile instead of calling getProfile()
fun hasAccess(): Boolean {
return currentProfile?.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true
}
}
```
```java
public class SubscriptionManager {
private AdaptyProfile currentProfile;
public SubscriptionManager() {
// Listen for profile updates
Adapty.setOnProfileUpdatedListener(profile -> {
this.currentProfile = profile;
// Update UI, unlock content, etc.
});
}
// Use stored profile instead of calling getProfile()
public boolean hasAccess() {
if (currentProfile == null) {
return false;
}
AdaptyAccessLevel premiumAccess = currentProfile.getAccessLevels().get("YOUR_ACCESS_LEVEL");
return premiumAccess != null && premiumAccess.isActive();
}
}
```
:::note
Adapty appelle automatiquement l'écouteur de mise à jour du profil au démarrage de votre application, en fournissant les données d'abonnement mises en cache même si l'appareil est hors ligne.
:::
## Connecter le profil à la logique des paywalls \{#connect-profile-with-paywall-logic\}
Lorsque vous devez prendre des décisions immédiates concernant l'affichage des paywalls ou l'accès aux fonctionnalités payantes, vous pouvez vérifier directement le profil de l'utilisateur. Cette approche est utile dans des scénarios comme le lancement de l'application, l'entrée dans des sections premium, ou avant l'affichage de contenu spécifique.
```kotlin
private fun initializePaywall() {
loadPaywall { paywallView ->
checkAccessLevel { result ->
when (result) {
is AdaptyResult.Success -> {
if (!result.value && paywallView != null) {
setContentView(paywallView) // Show paywall if no access
}
}
is AdaptyResult.Error -> {
if (paywallView != null) {
setContentView(paywallView) // Show paywall if access check fails
}
}
}
}
}
}
private fun checkAccessLevel(callback: ResultCallback) {
Adapty.getProfile { result ->
when (result) {
is AdaptyResult.Success -> {
val hasAccess = result.value.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true
callback.onResult(AdaptyResult.Success(hasAccess))
}
is AdaptyResult.Error -> {
callback.onResult(AdaptyResult.Error(result.error))
}
}
}
}
```
```java
private void initializePaywall() {
loadPaywall(paywallView -> {
checkAccessLevel(result -> {
if (result instanceof AdaptyResult.Success) {
boolean hasAccess = ((AdaptyResult.Success) result).getValue();
if (!hasAccess && paywallView != null) {
setContentView(paywallView); // Show paywall if no access
}
} else if (result instanceof AdaptyResult.Error) {
if (paywallView != null) {
setContentView(paywallView); // Show paywall if access check fails
}
}
});
});
}
private void checkAccessLevel(ResultCallback callback) {
Adapty.getProfile(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
AdaptyAccessLevel premiumAccess = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL");
boolean hasAccess = premiumAccess != null && premiumAccess.isActive();
callback.onResult(AdaptyResult.success(hasAccess));
} else if (result instanceof AdaptyResult.Error) {
callback.onResult(AdaptyResult.error(((AdaptyResult.Error) result).getError()));
}
});
}
```
## Étapes suivantes \{#next-steps\}
Maintenant que vous savez comment suivre le statut d'abonnement, apprenez à [travailler avec les profils utilisateurs](android-quickstart-identify) pour vous assurer qu'ils peuvent accéder à ce pour quoi ils ont payé.
---
# File: android-quickstart-identify
---
---
title: "Identifier les utilisateurs dans le SDK Android"
description: "Guide de démarrage rapide pour configurer Adapty pour la gestion des abonnements intégrés sur Android."
---
:::important
Ce guide s'adresse à vous si vous disposez de votre propre système d'authentification. Vous apprendrez ici à gérer les profils utilisateurs dans Adapty pour qu'ils s'alignent sur votre système d'authentification existant.
:::
La façon dont vous gérez les achats des utilisateurs dépend du modèle d'authentification de votre application :
- Si votre application n'utilise pas d'authentification backend et ne stocke pas de données utilisateur, consultez la [section sur les utilisateurs anonymes](#anonymous-users).
- Si votre application dispose (ou disposera) d'une authentification backend, consultez la [section sur les utilisateurs identifiés](#identified-users).
**Concepts clés** :
- Les **profils** sont les entités nécessaires au fonctionnement du SDK. Adapty les crée automatiquement.
- Ils peuvent être anonymes **(sans customer user ID)** ou identifiés **(avec customer user ID)**.
- Vous fournissez un **customer user ID** pour faire correspondre les profils Adapty avec votre système d'authentification interne.
Voici les différences entre les utilisateurs anonymes et les utilisateurs identifiés :
| | Utilisateurs anonymes | Utilisateurs identifiés |
|------------------------------|--------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| **Gestion des achats** | Restauration des achats au niveau du store | Historique des achats conservé sur tous les appareils via leur customer user ID |
| **Gestion des profils** | Nouveau profil à chaque réinstallation | Le même profil sur toutes les sessions et tous les appareils |
| **Persistance des données** | Les données des utilisateurs anonymes sont liées à l'installation de l'application | Les données des utilisateurs identifiés persistent entre les installations de l'application |
## Utilisateurs anonymes \{#anonymous-users\}
Si vous n'avez pas d'authentification backend, **vous n'avez pas besoin de gérer l'authentification dans le code de l'application** :
1. Lorsque le SDK est activé au premier lancement de l'application, Adapty **crée un nouveau profil pour l'utilisateur**.
2. Lorsque l'utilisateur effectue un achat dans l'application, cet achat est **associé à son profil Adapty et à son compte store**.
3. Lorsque l'utilisateur **réinstalle** l'application ou l'installe sur un **nouvel appareil**, Adapty **crée un nouveau profil anonyme à l'activation**.
4. Si l'utilisateur a déjà effectué des achats dans votre application, par défaut, ses achats sont automatiquement synchronisés depuis l'App Store à l'activation du SDK.
Ainsi, avec les utilisateurs anonymes, de nouveaux profils seront créés à chaque installation, mais ce n'est pas un problème car, dans les analyses Adapty, vous pouvez [configurer ce qui sera considéré comme une nouvelle installation](general#4-installs-definition-for-analytics).
Pour les utilisateurs anonymes, vous devez compter les installations par **ID d'appareil**. Dans ce cas, chaque installation de l'application sur un appareil est comptée comme une installation, y compris les réinstallations.
## Utilisateurs identifiés \{#identified-users\}
Vous avez deux options pour identifier les utilisateurs dans l'application :
- [**Lors de la connexion/inscription :**](#during-loginsignup) Si les utilisateurs se connectent après le démarrage de votre application, appelez `identify()` avec un customer user ID lorsqu'ils s'authentifient.
- [**Lors de l'activation du SDK :**](#during-the-sdk-activation) Si vous disposez déjà d'un customer user ID stocké au lancement de l'application, envoyez-le lors de l'appel à `activate()`.
:::important
Par défaut, lorsqu'Adapty reçoit un achat associé à un Customer User ID déjà lié à un autre Customer User ID, le niveau d'accès est partagé, de sorte que les deux profils bénéficient d'un accès payant. Vous pouvez configurer ce paramètre pour transférer l'accès payant d'un profil à un autre ou désactiver complètement le partage. Consultez l'[article](general#6-sharing-paid-access-between-user-accounts) pour plus de détails.
:::
### Lors de la connexion/inscription \{#during-loginsignup\}
Si vous identifiez les utilisateurs après le lancement de l'application (par exemple, après leur connexion ou inscription), utilisez la méthode `identify` pour définir leur customer user ID.
- Si vous **n'avez jamais utilisé ce customer user ID auparavant**, Adapty le liera automatiquement au profil actuel.
- Si vous **avez déjà utilisé ce customer user ID pour identifier l'utilisateur**, Adapty basculera vers le profil associé à ce customer user ID.
:::important
Les customer user ID doivent être uniques pour chaque utilisateur. Si vous codez la valeur du paramètre en dur, tous les utilisateurs seront considérés comme un seul.
:::
Attendez que le callback de complétion d'`identify` se déclenche avant d'appeler d'autres méthodes du SDK. Des appels simultanés pourraient atterrir sur le profil anonyme plutôt que sur le profil identifié. Voir [Ordre des appels dans le SDK Android](android-sdk-call-order).
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user
if (error == null) {
// successful identify
}
}
```
```java showLineNumbers
// User IDs must be unique for each user
Adapty.identify("YOUR_USER_ID", error -> {
if (error == null) {
// successful identify
}
});
```
### Lors de l'activation du SDK \{#during-the-sdk-activation\}
Si vous connaissez déjà un customer user ID au moment de l'activation du SDK, vous pouvez l'envoyer dans la méthode `activate` plutôt que d'appeler `identify` séparément.
Si vous connaissez un customer user ID mais ne le définissez qu'après l'activation, cela signifie qu'à l'activation, Adapty créera un nouveau profil anonyme et ne basculera vers le profil existant qu'après votre appel à `identify`.
Vous pouvez passer soit un customer user ID existant (que vous avez déjà utilisé), soit un nouveau. Si vous en passez un nouveau, le profil créé à l'activation sera automatiquement lié à ce customer user ID.
:::note
Par défaut, la création de profils anonymes n'affecte pas les tableaux de bord d'analyse, car les installations sont comptées en fonction des ID d'appareil.
Un ID d'appareil représente une seule installation de l'application depuis le store sur un appareil et n'est régénéré qu'après la réinstallation de l'application.
Il ne dépend pas du fait qu'il s'agisse d'une première ou d'une nouvelle installation, ni du fait qu'un customer user ID existant soit utilisé.
La création d'un profil (à l'activation du SDK ou lors de la déconnexion), la connexion ou la mise à jour de l'application sans réinstallation ne génère pas d'événements d'installation supplémentaires.
Si vous souhaitez compter les installations en fonction des utilisateurs uniques plutôt que des appareils, accédez à **App settings** et configurez [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```kotlin showLineNumbers
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
.build()
```
```java showLineNumbers
new AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
.build();
```
### Déconnecter les utilisateurs \{#log-users-out\}
Si vous avez un bouton pour déconnecter les utilisateurs, utilisez la méthode `logout`.
:::important
La déconnexion d'un utilisateur crée un nouveau profil anonyme pour cet utilisateur.
:::
```kotlin showLineNumbers
Adapty.logout { error ->
if (error == null) {
// successful logout
}
}
```
```java showLineNumbers
Adapty.logout(error -> {
if (error == null) {
// successful logout
}
});
```
:::info
Pour reconnecter les utilisateurs à l'application, utilisez la méthode `identify`.
:::
### Autoriser les achats sans connexion \{#allow-purchases-without-login\}
Si vos utilisateurs peuvent effectuer des achats aussi bien avant qu'après leur connexion à votre application, vous devez vous assurer qu'ils conserveront leur accès après la connexion :
1. Lorsqu'un utilisateur déconnecté effectue un achat, Adapty le lie à son ID de profil anonyme.
2. Lorsque l'utilisateur se connecte à son compte, Adapty bascule vers son profil identifié.
- S'il s'agit d'un nouveau customer user ID (par exemple, l'achat a été effectué avant l'inscription), Adapty attribue le customer user ID au profil actuel, de sorte que tout l'historique des achats est conservé.
- S'il s'agit d'un customer user ID existant (le customer user ID est déjà lié à un profil), vous devez obtenir le niveau d'accès actuel après le changement de profil. Vous pouvez soit appeler [`getProfile`](android-check-subscription-status) juste après l'identification, soit [écouter les mises à jour du profil](android-check-subscription-status) pour que les données se synchronisent automatiquement.
## Prochaines étapes \{#next-steps\}
Félicitations ! Vous avez implémenté la logique de paiement intégré dans votre application ! Nous vous souhaitons tout le succès possible pour la monétisation de votre application !
Pour tirer encore plus de valeur d'Adapty, vous pouvez explorer ces sujets :
- [**Tests**](troubleshooting-test-purchases) : Vérifiez que tout fonctionne comme prévu
- [**Onboardings**](android-onboardings) : Engagez les utilisateurs avec des onboardings et améliorez la rétention
- [**Intégrations**](configuration) : Intégrez des services d'attribution marketing et d'analyse en une seule ligne de code
- [**Définir des attributs de profil personnalisés**](android-setting-user-attributes) : Ajoutez des attributs personnalisés aux profils utilisateurs et créez des segments pour lancer des tests A/B ou afficher différents paywalls à différents utilisateurs
---
# File: adapty-sdk-integration-skill-android
---
---
title: "Intégrer Adapty dans votre application Android avec le skill d'intégration SDK"
description: "Utilisez le skill adapty-sdk-integration pour intégrer le SDK Adapty dans votre application Android de bout en bout avec votre outil de codage IA."
---
:::important
Le skill est en bêta. S'il se bloque ou se comporte de manière inattendue, suivez le [guide d'intégration étape par étape](adapty-cursor-android) à la place — il guide votre outil IA à travers chaque étape avec la documentation appropriée.
:::
La [compétence adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatise l'intégration Adapty de bout en bout : configuration du tableau de bord, installation du SDK, paywall et vérification à chaque étape. Elle détecte automatiquement votre plateforme et récupère la documentation Adapty pertinente à chaque étape.
**Outils compatibles** : Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Pour installer, choisissez le formulaire correspondant à votre outil. La liste complète se trouve dans le [README de la compétence](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex ou tout autre outil** — utilisez la [CLI skills](https://skills.sh) (notez que les compétences installées de cette façon ne se mettent pas à jour automatiquement) :
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
Vous pouvez également cloner le dépôt et copier `skills/adapty-sdk-integration/` dans le répertoire des compétences de votre outil.
Après l'installation, exécutez la compétence dans votre projet :
```
/adapty-sdk-integration
```
La compétence pose quelques questions de configuration, puis guide à travers la configuration du tableau de bord, l'installation du SDK, le paywall et la vérification.
---
# File: adapty-cursor-android
---
---
title: "Intégrer Adapty dans votre application Android avec l'aide de l'IA"
description: "Un guide étape par étape pour intégrer Adapty dans votre application Android avec Cursor, Context7, ChatGPT, Claude ou d'autres outils IA."
---
Ce guide vous accompagne pas à pas dans l'intégration d'Adapty dans votre application Android à l'aide d'un outil IA — vous lui fournissez la bonne documentation Adapty dans le bon ordre.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Avant de commencer : configuration du tableau de bord \{#before-you-start-dashboard-setup\}
Adapty nécessite une configuration dans le tableau de bord avant d'écrire le moindre code SDK. Vous pouvez le faire avec un skill LLM interactif, ou manuellement via le Dashboard.
### Approche par skill (recommandée) \{#skill-approach-recommended\}
Le skill Adapty CLI permet à votre LLM de configurer votre application, vos produits, niveaux d'accès, paywalls et placements directement — sans ouvrir le Dashboard à chaque étape. Vous avez uniquement besoin de [connecter votre store](integrate-payments) dans le Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Une fois le skill ajouté, lancez `/adapty-cli` dans votre agent. Il vous guidera à chaque étape — y compris quand ouvrir le Dashboard pour connecter votre store.
### Approche manuelle \{#dashboard-approach\}
Si vous préférez tout configurer manuellement, voici ce dont vous avez besoin avant d'écrire du code. Votre LLM ne peut pas récupérer les valeurs du tableau de bord à votre place — vous devrez les lui fournir.
1. **Connectez votre store** : dans l'Adapty Dashboard, allez dans **App settings → General**. C'est indispensable pour que les achats fonctionnent.
[Connecter Google Play](integrate-payments)
2. **Copiez votre clé SDK publique** : dans l'Adapty Dashboard, allez dans **App settings → General**, puis trouvez la section **API keys**. Dans le code, c'est la chaîne que vous passez au builder de configuration Adapty.
3. **Créez au moins un produit** : dans l'Adapty Dashboard, allez sur la page **Products**. Vous ne référencez pas les produits directement dans le code — Adapty les livre via les paywalls.
[Ajouter des produits](quickstart-products)
4. **Créez un paywall et un placement** : dans l'Adapty Dashboard, créez un paywall sur la page **Paywalls**, puis assignez-le à un placement sur la page **Placements**. Dans le code, l'ID de placement est la chaîne que vous passez à `Adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Créer un paywall](quickstart-paywalls)
5. **Configurez les niveaux d'accès** : dans l'Adapty Dashboard, configurez-les par produit sur la page **Products**. Dans le code, la chaîne vérifiée dans `profile.accessLevels["premium"]?.isActive`. Le niveau d'accès `premium` par défaut convient à la plupart des applications. Si les utilisateurs payants ont accès à des fonctionnalités différentes selon le produit (par exemple, un plan `basic` et un plan `pro`), [créez des niveaux d'accès supplémentaires](assigning-access-level-to-a-product) avant de commencer à coder.
:::tip
Une fois ces cinq éléments en place, vous êtes prêt à écrire du code. Dites à votre LLM : "Ma clé SDK publique est X, mon ID de placement est Y" pour qu'il génère un code d'initialisation et de récupération de paywall correct.
:::
### À configurer quand vous serez prêt \{#set-up-when-ready\}
Ces éléments ne sont pas nécessaires pour commencer à coder, mais vous en aurez besoin à mesure que votre intégration se développe :
- **Tests A/B** : à configurer sur la page **Placements**. Aucun changement de code nécessaire.
[Tests A/B](ab-tests)
- **Paywalls et placements supplémentaires** : ajoutez d'autres appels `getPaywall` avec des ID de placement différents.
- **Intégrations analytiques** : à configurer sur la page **Integrations**. La configuration varie selon l'intégration. Voir [intégrations analytiques](analytics-integration) et [intégrations d'attribution](attribution-integration).
## Fournir la documentation Adapty à votre LLM \{#feed-adapty-docs-to-your-llm\}
### Utiliser Context7 (recommandé) \{#use-context7-recommended\}
[Context7](https://context7.com) est un serveur MCP qui donne à votre LLM un accès direct à la documentation Adapty à jour. Votre LLM récupère automatiquement les bons documents en fonction de vos questions — pas besoin de coller des URL manuellement.
Context7 fonctionne avec **Cursor**, **Claude Code**, **Windsurf** et d'autres outils compatibles MCP. Pour le configurer, exécutez :
```
npx ctx7 setup
```
Cela détecte votre éditeur et configure le serveur Context7. Pour une configuration manuelle, consultez le [dépôt GitHub Context7](https://github.com/upstash/context7).
Une fois configuré, référencez la bibliothèque Adapty dans vos prompts :
```
Use the adaptyteam/adapty-docs library to look up how to install the Android SDK
```
:::warning
Même si Context7 évite de coller des liens vers la documentation manuellement, l'ordre d'implémentation est important. Suivez le [guide d'implémentation](#implementation-walkthrough) ci-dessous étape par étape pour vous assurer que tout fonctionne.
:::
### Utiliser la documentation en texte brut \{#use-plain-text-docs\}
Vous pouvez accéder à n'importe quel article de la documentation Adapty en Markdown. Ajoutez `.md` à la fin de son URL, ou cliquez sur **Copy for LLM** sous le titre de l'article. Par exemple : [adapty-cursor-android.md](https://adapty.io/docs/fr/adapty-cursor-android.md).
Chaque étape du [guide d'implémentation](#implementation-walkthrough) ci-dessous inclut un bloc "À envoyer à votre LLM" avec des liens `.md` à coller.
Pour obtenir davantage de documentation en une fois, consultez les [fichiers d'index et sous-ensembles par plateforme](#plain-text-doc-index-files) ci-dessous.
## Guide d'implémentation \{#implementation-walkthrough\}
La suite de ce guide parcourt l'intégration d'Adapty dans l'ordre d'implémentation. Chaque étape inclut les documents à envoyer à votre LLM, ce que vous devriez observer une fois terminé, et les problèmes courants.
### Planifier votre intégration \{#plan-your-integration\}
Avant de vous lancer dans le code, demandez à votre LLM d'analyser votre projet et de créer un plan d'implémentation. Si votre outil IA propose un mode de planification (comme le mode plan de Cursor ou Claude Code), utilisez-le afin que le LLM puisse lire à la fois la structure de votre projet et la documentation Adapty avant d'écrire du code.
Indiquez à votre LLM l'approche que vous utilisez pour les achats — cela influe sur les guides à suivre :
- [**Adapty Paywall Builder**](adapty-paywall-builder) : vous créez des paywalls dans l'éditeur no-code d'Adapty, et le SDK les affiche automatiquement.
- [**Paywalls créés manuellement**](android-making-purchases) : vous construisez votre propre interface de paywall dans le code, mais utilisez quand même Adapty pour récupérer les produits et gérer les achats.
- [**Mode Observer**](observer-vs-full-mode) : vous conservez votre infrastructure d'achat existante et utilisez Adapty uniquement pour l'analytique et les intégrations.
Vous ne savez pas lequel choisir ? Lisez le [tableau comparatif dans le guide de démarrage rapide](android-quickstart-paywalls).
### Installer et configurer le SDK \{#install-and-configure-the-sdk\}
Ajoutez la dépendance du SDK Adapty via Gradle dans Android Studio et activez-le avec votre clé SDK publique. C'est la base — rien d'autre ne fonctionne sans ça.
**Guide :** [Installer et configurer le SDK Adapty](sdk-installation-android)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/sdk-installation-android.md
```
:::tip[Point de contrôle]
- **Attendu :** l'application se compile et s'exécute. Logcat affiche le log d'activation Adapty.
- **Problème courant :** "Public API key is missing" → vérifiez que vous avez remplacé le placeholder par votre vraie clé depuis App settings.
:::
### Afficher les paywalls et gérer les achats \{#show-paywalls-and-handle-purchases\}
Récupérez un paywall par ID de placement, affichez-le et gérez les événements d'achat. Les guides dont vous avez besoin dépendent de la façon dont vous gérez les achats.
Testez chaque achat en sandbox au fur et à mesure — n'attendez pas la fin. Consultez [Tester les achats en sandbox](test-purchases-in-sandbox) pour les instructions de configuration.
**Guides :**
- [Activer les achats avec les paywalls (guide de démarrage rapide)](android-quickstart-paywalls)
- [Récupérer les paywalls du Paywall Builder et leur configuration](android-get-pb-paywalls)
- [Afficher les paywalls](android-present-paywalls)
- [Gérer les événements de paywall](android-handling-events)
- [Répondre aux actions des boutons](android-handle-paywall-actions)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/android-quickstart-paywalls.md
- https://adapty.io/docs/fr/android-get-pb-paywalls.md
- https://adapty.io/docs/fr/android-present-paywalls.md
- https://adapty.io/docs/fr/android-handling-events.md
- https://adapty.io/docs/fr/android-handle-paywall-actions.md
```
:::tip[Point de contrôle]
- **Attendu :** le paywall s'affiche avec vos produits configurés. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox.
- **Problème courant :** paywall vide ou erreur `getPaywall` → vérifiez que l'ID de placement correspond exactement à celui du tableau de bord et que le placement a une audience assignée.
:::
**Guides :**
- [Activer les achats dans votre paywall personnalisé (guide de démarrage rapide)](android-quickstart-manual)
- [Récupérer les paywalls et les produits](fetch-paywalls-and-products-android)
- [Afficher un paywall conçu via Remote Config](present-remote-config-paywalls-android)
- [Effectuer des achats](android-making-purchases)
- [Restaurer des achats](android-restore-purchase)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/android-quickstart-manual.md
- https://adapty.io/docs/fr/fetch-paywalls-and-products-android.md
- https://adapty.io/docs/fr/present-remote-config-paywalls-android.md
- https://adapty.io/docs/fr/android-making-purchases.md
- https://adapty.io/docs/fr/android-restore-purchase.md
```
:::tip[Point de contrôle]
- **Attendu :** votre paywall personnalisé affiche les produits récupérés depuis Adapty. Appuyer sur un produit déclenche la boîte de dialogue d'achat sandbox.
- **Problème courant :** tableau de produits vide → vérifiez que le paywall a des produits assignés dans le tableau de bord et que le placement a une audience.
:::
**Guides :**
- [Présentation du mode Observer](observer-vs-full-mode)
- [Implémenter le mode Observer](implement-observer-mode-android)
- [Signaler les transactions en mode Observer](report-transactions-observer-mode-android)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/observer-vs-full-mode.md
- https://adapty.io/docs/fr/implement-observer-mode-android.md
- https://adapty.io/docs/fr/report-transactions-observer-mode-android.md
```
:::tip[Point de contrôle]
- **Attendu :** après un achat sandbox via votre flux d'achat existant, la transaction apparaît dans le **Event Feed** du tableau de bord Adapty.
- **Problème courant :** aucun événement → vérifiez que vous signalez les transactions à Adapty et que les notifications Google Play Real-Time Developer Notifications sont configurées.
:::
### Vérifier le statut de l'abonnement \{#check-subscription-status\}
Après un achat, vérifiez dans le profil utilisateur la présence d'un niveau d'accès actif pour restreindre le contenu premium.
**Guide :** [Vérifier le statut de l'abonnement](android-check-subscription-status)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/android-check-subscription-status.md
```
:::tip[Point de contrôle]
- **Attendu :** après un achat sandbox, `profile.accessLevels["premium"]?.isActive` renvoie `true`.
- **Problème courant :** `accessLevels` vide après l'achat → vérifiez que le produit a un niveau d'accès assigné dans le tableau de bord.
:::
### Identifier les utilisateurs \{#identify-users\}
Liez les comptes utilisateurs de votre application aux profils Adapty pour que les achats persistent sur tous les appareils.
:::important
Ignorez cette étape si votre application n'a pas d'authentification.
:::
**Guide :** [Identifier les utilisateurs](android-quickstart-identify)
À envoyer à votre LLM :
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/fr/android-quickstart-identify.md
```
:::tip[Point de contrôle]
- **Attendu :** après avoir appelé `Adapty.identify("your-user-id")`, la section **Profiles** du tableau de bord affiche votre ID utilisateur personnalisé.
- **Problème courant :** appelez `identify` après l'activation mais avant de récupérer les paywalls pour éviter l'attribution à un profil anonyme.
:::
### Se préparer pour la mise en production \{#prepare-for-release\}
Une fois votre intégration fonctionnelle en sandbox, parcourez la checklist de mise en production pour vous assurer que tout est prêt pour la production.
**Guide :** [Checklist de mise en production](release-checklist)
À envoyer à votre LLM :
```
Read these Adapty docs before releasing:
- https://adapty.io/docs/fr/release-checklist.md
```
:::tip[Point de contrôle]
- **Attendu :** tous les éléments de la checklist confirmés : connexion au store, notifications serveur, flux d'achat, vérifications du niveau d'accès et exigences de confidentialité.
- **Problème courant :** notifications Google Play Real-Time Developer Notifications manquantes → configurez-les dans **App settings → Android SDK**, sinon les événements n'apparaîtront pas dans le tableau de bord.
:::
## Fichiers d'index de documentation en texte brut \{#plain-text-doc-index-files\}
Si vous avez besoin de fournir à votre LLM un contexte plus large que des pages individuelles, nous hébergeons des fichiers d'index qui listent ou regroupent toute la documentation Adapty :
- [`llms.txt`](https://adapty.io/docs/fr/llms.txt) : liste toutes les pages avec des liens `.md`. Un [standard émergent](https://llmstxt.org/) pour rendre les sites web accessibles aux LLMs. Notez que pour certains agents IA (par exemple ChatGPT), vous devrez télécharger `llms.txt` et le joindre en pièce jointe dans la conversation.
- [`llms-full.txt`](https://adapty.io/docs/fr/llms-full.txt) : l'intégralité de la documentation Adapty regroupée en un seul fichier. Très volumineux — à utiliser uniquement lorsque vous avez besoin d'une vue d'ensemble complète.
- [`android-llms.txt`](https://adapty.io/docs/fr/android-llms.txt) et [`android-llms-full.txt`](https://adapty.io/docs/fr/android-llms-full.txt) spécifiques à Android : des sous-ensembles par plateforme qui économisent des tokens par rapport au site complet.
---
# File: android-paywalls
---
---
title: "Flows et paywalls - Android"
description: "Affichez et gérez les flows et paywalls créés avec Adapty Flow Builder ou Paywall Builder dans votre application Android."
---
## Afficher les paywalls \{#display-paywalls\}
### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\}
:::tip
Pour démarrer rapidement avec les paywalls Adapty Paywall Builder, consultez notre [guide de démarrage rapide](android-quickstart-paywalls).
:::
### Implémenter les paywalls manuellement \{#implement-paywalls-manually\}
Pour plus de guides sur l'implémentation des paywalls et la gestion des achats manuellement, consultez la [catégorie](android-implement-paywalls-manually).
## Fonctionnalités utiles \{#useful-features\}
---
# File: android-get-pb-paywalls
---
---
title: "Obtenir des flows et des paywalls - Android"
description: "Récupérez des flows et des paywalls depuis Adapty dans votre application Android."
---
Après avoir [conçu votre flow ou votre paywall avec le Paywall Builder](adapty-paywall-builder), vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le flow ou le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à afficher des flows dans votre application mobile (cliquer pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un flow/paywall et intégrez-y des produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez-y votre flow/paywall](create-placement) dans l'Adapty Dashboard.
4. Installez le [SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer un flow/paywall \{#fetch-flowpaywall\}
Si vous avez conçu un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher. Vous devez néanmoins récupérer son ID via le placement, sa configuration d'affichage, puis le présenter dans votre application mobile.
Pour garantir des performances optimales, il est essentiel de récupérer le flow ou le paywall et sa [configuration de vue](android-get-pb-paywalls#fetch-the-view-configuration) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher à l'utilisateur.
Pour obtenir un flow ou un paywall, utilisez la méthode `getFlow` :
```kotlin showLineNumbers
...
Adapty.getFlow("YOUR_PLACEMENT_ID", loadTimeout = 10.seconds) { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
// the requested flow/paywall
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
...
Adapty.getFlow("YOUR_PLACEMENT_ID", TimeInterval.seconds(10), result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
// the requested flow/paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. |
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK essaie de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'obtiendront peut-être pas les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les flows et les paywalls localement sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour les récupérer plus rapidement, ainsi qu'un serveur de secours autonome en cas d'indisponibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de différentes requêtes en interne.
Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne définir aucune limite, utilisez `TimeInterval.INFINITE`.
|
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :---------- |
| Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, les Remote Configs, ainsi qu'un indicateur `hasViewConfiguration` précisant si le flow inclut une configuration de vue. Pour récupérer les produits réels en vue d'un préchargement, d'une interface personnalisée ou de vérifications programmatiques, appelez `getPaywallProducts(flow)`. |
## Récupérer la configuration de vue \{#fetch-the-view-configuration\}
Après avoir récupéré le flow ou le paywall, vérifiez s'il inclut une configuration de vue via `flow.hasViewConfiguration`. Ce flag permet de distinguer la façon dont le placement a été conçu dans l'Adapty Dashboard :
- **`true`** — le placement a été conçu dans le **Flow Builder** (un flow) ou le **Paywall Builder** (un paywall). Adapty génère l'interface à votre place. Suivez les étapes ci-dessous pour récupérer la configuration de vue et [afficher le flow ou le paywall](android-present-paywalls).
- **`false`** — le placement est un paywall personnalisé sans interface Builder. [Traitez-le comme un paywall Remote Config](present-remote-config-paywalls-android).
:::important
Veillez à activer le bouton **Show on device** dans le Flow Builder. Si cette option n'est pas activée, la configuration de vue ne sera pas disponible pour la récupération.
:::
Utilisez la méthode `getFlowConfiguration` pour charger la configuration de la vue.
```kotlin showLineNumbers
if (!flow.hasViewConfiguration) {
// use your custom logic
return
}
AdaptyUI.getFlowConfiguration(flow, loadTimeout = 10.seconds) { result ->
when(result) {
is AdaptyResult.Success -> {
val flowConfiguration = result.value
// use loaded configuration
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
| Paramètre | Présence | Description |
| :-------------- | :------------- | :----------------------------------------------------------- |
| **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. |
| **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) dans laquelle afficher la vue, attendu sous forme de code de langue avec un ou deux sous-tags séparés par `-` (ex. : `en`, `pt-br`). Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne contient pas de version `en`. Voir [Localisations et codes de langue](android-localizations-and-locale-codes). |
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente de la méthode. Si ce délai est dépassé, les données en cache ou le fallback local sont retournés. Notez que dans de rares cas, la méthode peut expirer légèrement après le délai indiqué dans `loadTimeout`, car l'opération peut regrouper plusieurs requêtes en interne. |
Utilisez la méthode `getFlowConfiguration` pour charger la configuration de la vue.
```java showLineNumbers
if (!flow.hasViewConfiguration()) {
// use your custom logic
return;
}
AdaptyUI.getFlowConfiguration(flow, TimeInterval.seconds(10), result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyUI.FlowConfiguration flowConfiguration =
((AdaptyResult.Success) result).getValue();
// use loaded configuration
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
| Paramètre | Présence | Description |
| :-------------- | :------------- | :----------------------------------------------------------- |
| **flow** | requis | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. |
| **locale** | optionnel | L'identifiant de la [localisation du flow](add-paywall-locale-in-adapty-paywall-builder) à utiliser pour afficher la vue, exprimé sous forme de code de langue avec un ou deux sous-tags séparés par `-` (ex. : `en`, `pt-br`). Si omis, la vue s'affiche en `en`, ou dans la localisation par défaut du flow si celui-ci ne dispose pas de `en`. Voir [Localisations et codes de locale](android-localizations-and-locale-codes). |
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le contenu de secours local seront renvoyés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut reposer sur plusieurs requêtes en arrière-plan. |
:::note
Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de langue [ici](android-localizations-and-locale-codes).
:::
Une fois chargé, [présentez le flow ou le paywall](android-present-paywalls).
## Obtenir un flow ou un paywall pour l'audience par défaut afin d'accélérer la récupération \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\}
En général, les flows et les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et placements et que vos utilisateurs disposent d'une connexion Internet faible, la récupération d'un flow ou d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow ou un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout.
Pour y remédier, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow ou le paywall du placement spécifié pour l'audience **All Users**. Il est cependant essentiel de comprendre que l'approche recommandée est de récupérer le flow ou le paywall via la méthode `getFlow`, comme détaillé dans la section [Récupérer le flow/paywall](#fetch-flowpaywall) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getFlow`
La méthode `getFlowForDefaultAudience` présente quelques inconvénients majeurs :
- **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et futures), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows non rendus.
- **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des flows ou des paywalls, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur `getFlow` décrit [ci-dessus](#fetch-flowpaywall).
:::
```kotlin showLineNumbers
Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
// the requested flow
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
// the requested flow
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Toutefois, si vous pensez que vos utilisateurs font face à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui le rend fiable pour éviter des requêtes réseau en cours de session.
Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
|
## Personnaliser les ressources \{#customize-assets\}
Pour personnaliser les images et vidéos dans votre flow ou paywall, implémentez des ressources personnalisées.
Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement.
Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty.
Par exemple, vous pouvez :
- Afficher une image ou vidéo différente à certains utilisateurs.
- Afficher une image d'aperçu locale pendant le chargement d'une image principale distante.
- Afficher une image d'aperçu avant de lancer une vidéo.
Here's an example of how you can provide custom assets via a simple dictionary:
```kotlin showLineNumbers
val customAssets = AdaptyCustomAssets.of(
"hero_image" to
AdaptyCustomImageAsset.remote(
url = "https://example.com/image.jpg",
preview = AdaptyCustomImageAsset.file(
FileLocation.fromAsset("images/hero_image_preview.png"),
)
),
"hero_video" to
AdaptyCustomVideoAsset.file(
FileLocation.fromResId(requireContext(), R.raw.custom_video),
preview = AdaptyCustomImageAsset.file(
FileLocation.fromResId(requireContext(), R.drawable.video_preview),
),
),
)
val flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
products,
eventListener,
insets,
customAssets,
)
```
:::note
Si un asset n'est pas trouvé, le flow utilisera son apparence par défaut.
:::
Pour les vidéos, vous pouvez éventuellement passer une `resolution` pour réserver l'espace de mise en page et définir le ratio d'aspect (`width / height`) avant le chargement de la vidéo :
```kotlin showLineNumbers
AdaptyCustomVideoAsset.file(
FileLocation.fromResId(requireContext(), R.raw.custom_video),
preview = AdaptyCustomImageAsset.file(
FileLocation.fromResId(requireContext(), R.drawable.video_preview),
),
resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920),
)
```
Après avoir [conçu la partie visuelle de votre paywall](adapty-paywall-builder) avec le nouveau Paywall Builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application mobile. La première étape consiste à récupérer le paywall associé au placement ainsi que sa configuration d'affichage, comme décrit ci-dessous.
:::warning
Le nouveau Paywall Builder nécessite Android SDK version 3.0 ou supérieure.
:::
Veuillez noter que cette rubrique concerne les paywalls personnalisés avec le Paywall Builder. Si vous implémentez vos paywalls manuellement, consultez la rubrique [Récupérer les paywalls et produits pour les paywalls Remote Config dans votre application mobile](fetch-paywalls-and-products-android).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à afficher des paywalls dans votre application mobile (cliquez pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez-y votre paywall](create-placement) dans l'Adapty Dashboard.
4. Installez le [SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer un paywall conçu avec le Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\}
Si vous avez [conçu un paywall avec le Paywall Builder](adapty-paywall-builder), vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être. Il vous suffit néanmoins de récupérer son ID via le placement, sa configuration d'affichage, puis de le présenter dans votre application mobile.
Pour garantir des performances optimales, il est essentiel de récupérer le paywall et sa [configuration de vue](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) le plus tôt possible, afin de laisser suffisamment de temps aux images pour se télécharger avant de les présenter à l'utilisateur.
Pour obtenir un paywall, utilisez la méthode `getPaywall` :
```kotlin showLineNumbers
...
Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en", loadTimeout = 10.seconds) { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// the requested paywall
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
...
Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", TimeInterval.seconds(10), result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// the requested paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements) souhaité. C'est la valeur que vous avez spécifiée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la [localisation du paywall](add-paywall-locale-in-adapty-paywall-builder). Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache est conservé lors du redémarrage de l'application et n'est effacé que lors de la désinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les paywalls localement sur deux couches : le cache régulièrement mis à jour décrit ci-dessus et les [paywalls de secours](fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'inaccessibilité du CDN. Ce système est conçu pour vous garantir toujours la dernière version de vos paywalls tout en assurant la fiabilité même lorsque la connexion internet est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront renvoyés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comporter différentes requêtes en coulisses.
Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.
|
Paramètres de réponse :
| Paramètre | Description |
| :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Paywall | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) contenant une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. |
## Récupérer la configuration d'affichage d'un paywall créé avec Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\}
:::important
Assurez-vous d'activer le bouton **Show on device** dans le Paywall Builder. Si cette option n'est pas activée, la configuration d'affichage ne pourra pas être récupérée.
:::
Après avoir récupéré le paywall, vérifiez s'il contient un `ViewConfiguration`, ce qui indique qu'il a été créé avec Paywall Builder. Cela vous guidera sur la façon d'afficher le paywall. Si le `ViewConfiguration` est présent, traitez-le comme un paywall Paywall Builder ; sinon, [gérez-le comme un paywall Remote Config](present-remote-config-paywalls).
Utilisez la méthode `getViewConfiguration` pour charger la configuration de la vue.
```kotlin showLineNumbers
if (!paywall.hasViewConfiguration) {
// use your custom logic
return
}
AdaptyUI.getViewConfiguration(paywall, loadTimeout = 10.seconds) { result ->
when(result) {
is AdaptyResult.Success -> {
val viewConfiguration = result.value
// use loaded configuration
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
| Paramètre | Présence | Description |
| :-------------- | :----------------- | :----------------------------------------------------------- |
| **paywall** | requis | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. |
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local seront retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut être composée de plusieurs requêtes en interne. |
Utilisez la méthode `getViewConfiguration` pour charger la configuration de vue.
```java showLineNumbers
if (!paywall.hasViewConfiguration()) {
// use your custom logic
return;
}
AdaptyUI.getViewConfiguration(paywall, TimeInterval.seconds(10), result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyUI.LocalizedViewConfiguration viewConfiguration =
((AdaptyResult.Success) result).getValue();
// use loaded configuration
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
| Paramètre | Présence | Description |
| :----------------------- | :------------- | :----------------------------------------------------------- |
| **paywall** | requis | Un objet `AdaptyPaywall` permettant d'obtenir un contrôleur pour le paywall souhaité. |
| **loadTimeout** | défaut : 5 sec | Cette valeur limite le délai d'attente de cette méthode. Si le délai est dépassé, les données en cache ou le fallback local seront retournés. Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut inclure différentes requêtes en coulisses. |
:::note
Si vous utilisez plusieurs langues, découvrez comment ajouter une [localisation dans le Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) et comment utiliser correctement les codes de locale [ici](android-localizations-and-locale-codes).
:::
Une fois chargé, [affichez le paywall](android-present-paywalls).
## Récupérer un paywall pour l'audience par défaut afin d'accélérer le chargement \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\}
En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'accélérer ce processus. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs ont une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide, plutôt que de ne rien afficher du tout.
Pour y remédier, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](#fetch-paywall-designed-with-paywall-builder) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getPaywall`
La méthode `getPaywallForDefaultAudience` présente quelques inconvénients notables :
- **Problèmes potentiels de compatibilité descendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des paywalls non affichés.
- **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (basé notamment sur les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, continuez à utiliser `getPaywall` décrit [ci-dessus](#fetch-paywall-designed-with-paywall-builder).
:::
```kotlin showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// the requested paywall
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// the requested paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
:::note
La méthode `getPaywallForDefaultAudience` est disponible à partir du SDK Android 2.11.3
:::
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez indiquée lors de la création d'un placement dans votre Adapty Dashboard. |
| **locale** | optionnel
défaut : `en`
| L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.
|
| **fetchPolicy** | défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas avoir les toutes dernières données, mais le chargement sera plus rapide, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, donc il est sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
|
## Personnaliser les ressources \{#customize-assets\}
Pour personnaliser les images et vidéos de votre paywall, implémentez des ressources personnalisées.
Les images et vidéos hero ont des identifiants prédéfinis : `hero_image` et `hero_video`. Dans un bundle de ressources personnalisées, vous ciblez ces éléments par leurs identifiants et personnalisez leur comportement.
Pour les autres images et vidéos, vous devez [définir un identifiant personnalisé](custom-media) dans le tableau de bord Adapty.
Par exemple, vous pouvez :
- Afficher une image ou une vidéo différente à certains utilisateurs.
- Afficher une image d'aperçu locale pendant le chargement d'une image principale distante.
- Afficher une image d'aperçu avant de lancer une vidéo.
:::important
Pour utiliser cette fonctionnalité, mettez à jour le SDK Android Adapty vers la version 3.7.0 ou supérieure.
:::
Voici un exemple montrant comment fournir des ressources personnalisées via un simple dictionnaire :
```kotlin showLineNumbers
val customAssets = AdaptyCustomAssets.of(
"hero_image" to
AdaptyCustomImageAsset.remote(
url = "https://example.com/image.jpg",
preview = AdaptyCustomImageAsset.file(
FileLocation.fromAsset("images/hero_image_preview.png"),
)
),
"hero_video" to
AdaptyCustomVideoAsset.file(
FileLocation.fromResId(requireContext(), R.raw.custom_video),
preview = AdaptyCustomImageAsset.file(
FileLocation.fromResId(requireContext(), R.drawable.video_preview),
),
),
)
val paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
eventListener,
insets,
customAssets,
)
```
:::note
Si un asset est introuvable, le paywall reviendra à son apparence par défaut.
:::
---
# File: android-present-paywalls
---
---
title: "Afficher les flows et paywalls - Android"
description: "Présentez des flows et des paywalls aux utilisateurs dans votre application Android."
---
Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être.
:::warning
Ce guide couvre les flows et les **paywalls créés avec le nouveau Paywall Builder** rendus par Adapty. Le processus diffère pour les paywalls en Remote Config et le [mode Observer](observer-vs-full-mode).
- Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec le Remote Config](present-remote-config-paywalls).
- Pour présenter des **paywalls en mode Observer**, consultez [Android - Présenter les paywalls Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode)
:::
Pour obtenir l'objet `flowConfiguration` utilisé ci-dessous, consultez [Récupérer les flows et paywalls](android-get-pb-paywalls).
Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement `AdaptyFlowView` :
```kotlin showLineNumbers
val flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
)
```
```kotlin showLineNumbers
val flowView =
AdaptyFlowView(activity) // or retrieve it from xml
...
with(flowView) {
showFlow(
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
)
}
```
```java showLineNumbers
AdaptyFlowView flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver
);
```
```java showLineNumbers
AdaptyFlowView flowView =
new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver);
```
```xml showLineNumbers
```
Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil.
Si vous obtenez `AdaptyFlowView` _autrement_ qu'en appelant `AdaptyUI.getFlowView()`, vous devrez également appeler la méthode `.showFlow()`.
Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, utilisez cette fonction composable :
```kotlin showLineNumbers
AdaptyFlowScreen(
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
)
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **flowConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow. Utilisez la méthode `AdaptyUI.getFlowConfiguration(flow)` pour le charger. Consultez la rubrique [Récupérer la configuration de la vue](android-get-pb-paywalls#fetch-the-view-configuration) pour plus de détails. |
| **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le timing d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupérera automatiquement les produits requis. |
| **eventListener** | optionnel | Fournissez un `AdaptyFlowEventListener` pour observer les événements du flow. Il est recommandé d'étendre `AdaptyFlowDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gérer les événements flow et paywall](android-handling-events) pour plus de détails. |
| **insets** | optionnel | Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués par les barres système.
Par défaut : `Unspecified`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les flows plein écran.
Si votre flow n'est pas plein écran, vous pouvez définir des insets personnalisés. Pour savoir comment faire, lisez la section [Modifier les insets du flow](android-present-paywalls#change-flow-insets) ci-dessous.
|
| **customAssets** | optionnel | Passez un objet `AdaptyCustomAssets` pour remplacer les images et vidéos de votre flow ou paywall au moment de l'exécution. Consultez [Personnaliser les assets](android-get-pb-paywalls#customize-assets) pour plus de détails. |
| **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du flow. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique sur les balises personnalisées dans le Paywall Builder pour plus de détails. |
| **timerResolver** | optionnel | Passez le résolveur ici si vous souhaitez utiliser la fonctionnalité de minuterie personnalisée. |
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
## Modifier les insets du flow \{#change-flow-insets\}
Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués par les barres système. Par défaut, Adapty ajuste automatiquement les insets, ce qui fonctionne parfaitement pour les flows plein écran.
Si votre flow n'est pas plein écran, vous pouvez définir des insets personnalisés :
- Si ni la barre de statut ni la barre de navigation ne se superposent à `AdaptyFlowView`, utilisez `AdaptyFlowInsets.None`.
- Pour des configurations plus personnalisées, par exemple si votre flow se superpose à la barre de statut en haut mais pas en bas, vous pouvez définir uniquement `bottomInset` à `0`, comme indiqué dans l'exemple ci-dessous :
```kotlin showLineNumbers
//create extension function
fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
ViewCompat.setOnApplyWindowInsetsListener(this, null)
action(systemBarInsets)
insets
}
}
//and then use it with the view
flowView.onReceiveSystemBarsInsets { insets ->
val flowInsets = AdaptyFlowInsets.vertical(insets.top, 0)
flowView.showFlow(
flowConfiguration,
products,
eventListener,
flowInsets,
customAssets,
tagResolver,
timerResolver,
)
}
```
```java showLineNumbers
...
ViewCompat.setOnApplyWindowInsetsListener(flowView, (view, insets) -> {
Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewCompat.setOnApplyWindowInsetsListener(flowView, null);
AdaptyFlowInsets flowInsets =
AdaptyFlowInsets.vertical(systemBarInsets.top, 0);
flowView.showFlow(flowConfiguration, products, eventListener, flowInsets);
return insets;
});
```
## Utiliser une minuterie définie par le développeur \{#use-developer-defined-timer\}
Pour utiliser des minuteries définies par le développeur dans votre application mobile, créez un objet `timerResolver` — un dictionnaire ou une map qui associe des minuteries personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du flow. Voici un exemple :
```kotlin showLineNumbers
...
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025
)
val timerResolver = AdaptyUiTimerResolver { timerId ->
customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } )
}
```
```java showLineNumbers
...
Map customTimers = new HashMap<>();
customTimers.put(
"CUSTOM_TIMER_NY",
new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime()
);
AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() {
@NonNull
@Override
public Date timerEndAtDate(@NonNull String timerId) {
Date date = customTimers.get(timerId);
return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */
}
};
```
Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** de la minuterie définie par le développeur que vous avez configurée dans l'Adapty Dashboard. Le `timerResolver` garantit que votre application met dynamiquement à jour la minuterie avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme l'heure de fin de la minuterie, comme le Jour de l'An, moins l'heure actuelle).
## Utiliser des balises personnalisées \{#use-custom-tags\}
Pour utiliser des balises personnalisées dans votre application mobile, créez un objet `tagResolver` — un dictionnaire ou une map qui associe des balises personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du flow. Voici un exemple :
```kotlin showLineNumbers
val customTags = mapOf("USERNAME" to "John")
val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] }
```
```java showLineNumbers
Map customTags = new HashMap<>();
customTags.put("USERNAME", "John");
AdaptyUiTagResolver tagResolver = customTags::get;
```
Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme ``. Le `tagResolver` garantit que votre application remplace dynamiquement cette balise personnalisée par la valeur spécifiée — par exemple `John`.
Nous recommandons de créer et de remplir le `tagResolver` juste avant de présenter votre flow. Une fois prêt, passez-le à la méthode AdaptyUI que vous utilisez pour présenter le flow.
## Modifier la couleur de l'indicateur de chargement du flow \{#change-flow-loading-indicator-color\}
Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante :
```xml showLineNumbers title = "XML"
```
Si vous avez personnalisé un paywall avec le Paywall Builder, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel paywall contient à la fois ce qui doit être affiché et la manière dont cela doit l'être.
:::warning
Ce guide concerne uniquement les **paywalls créés avec le nouveau Paywall Builder** qui nécessitent le SDK v3.0. Le processus de présentation des paywalls diffère selon les versions du Paywall Builder, les paywalls en Remote Config et le [mode Observer](observer-vs-full-mode).
- Pour présenter des **paywalls en Remote Config**, consultez [Afficher un paywall conçu avec le Remote Config](present-remote-config-paywalls).
- Pour présenter des **paywalls en mode Observer**, consultez [Android - Présenter les paywalls Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode)
:::
Pour obtenir l'objet `viewConfiguration` utilisé ci-dessous, consultez [Récupérer les paywalls Paywall Builder et leur configuration](android-get-pb-paywalls).
Pour afficher le paywall visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement `AdaptyPaywallView` :
```kotlin showLineNumbers
val paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
eventListener,
insets,
personalizedOfferResolver,
tagResolver,
timerResolver,
)
```
```kotlin showLineNumbers
val paywallView =
AdaptyPaywallView(activity) // or retrieve it from xml
...
with(paywallView) {
showPaywall(
viewConfiguration,
products,
eventListener,
insets,
personalizedOfferResolver,
tagResolver,
timerResolver,
)
}
```
```java showLineNumbers
AdaptyPaywallView paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
eventListener,
insets,
personalizedOfferResolver,
tagResolver,
timerResolver
);
```
```java showLineNumbers
AdaptyPaywallView paywallView =
new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
paywallView.showPaywall(viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver);
```
```xml showLineNumbers
```
Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher sur l'écran de l'appareil.
Si vous obtenez `AdaptyPaywallView` _autrement_ qu'en appelant `AdaptyUI.getPaywallView()`, vous devrez également appeler la méthode `.showPaywall()`.
Pour afficher le paywall visuel sur l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, utilisez cette fonction composable :
```kotlin showLineNumbers
AdaptyPaywallScreen(
viewConfiguration,
products,
eventListener,
insets,
personalizedOfferResolver,
tagResolver,
timerResolver,
)
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **viewConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.LocalizedViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. |
| **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le timing d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupérera automatiquement les produits requis. |
| **eventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gérer les événements du paywall](android-handling-events) pour plus de détails. |
| **insets** | optionnel | Les insets sont les espaces autour du paywall qui empêchent les éléments cliquables d'être masqués par les barres système.
Par défaut : `UNSPECIFIED`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les paywalls plein écran.
Si votre paywall n'est pas plein écran, vous pouvez définir des insets personnalisés. Pour savoir comment faire, lisez la section [Modifier les insets du paywall](android-present-paywalls#change-paywall-insets) ci-dessous.
|
| **personalizedOfferResolver** | optionnel | Pour indiquer un prix personnalisé ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et passez votre propre logique qui mappe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. |
| **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique sur les balises personnalisées dans le Paywall Builder pour plus de détails. |
| **timerResolver** | optionnel | Passez le résolveur ici si vous souhaitez utiliser la fonctionnalité de minuterie personnalisée. |
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
## Modifier les insets du paywall \{#change-paywall-insets\}
Les insets sont les espaces autour du paywall qui empêchent les éléments cliquables d'être masqués par les barres système. Par défaut, Adapty ajuste automatiquement les insets, ce qui fonctionne parfaitement pour les paywalls plein écran.
Si votre paywall n'est pas plein écran, vous pouvez définir des insets personnalisés :
- Si ni la barre de statut ni la barre de navigation ne se superposent à `AdaptyPaywallView`, utilisez `AdaptyPaywallInsets.NONE`.
- Pour des configurations plus personnalisées, par exemple si votre paywall se superpose à la barre de statut en haut mais pas en bas, vous pouvez définir uniquement `bottomInset` à `0`, comme indiqué dans l'exemple ci-dessous :
```kotlin showLineNumbers
//create extension function
fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
ViewCompat.setOnApplyWindowInsetsListener(this, null)
action(systemBarInsets)
insets
}
}
//and then use it with the view
paywallView.onReceiveSystemBarsInsets { insets ->
val paywallInsets = AdaptyPaywallInsets.vertical(insets.top, 0)
paywallView.showPaywall(
viewConfiguration,
products,
eventListener,
paywallInsets,
personalizedOfferResolver,
tagResolver,
timerResolver,
)
}
```
```java showLineNumbers
...
ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> {
Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewCompat.setOnApplyWindowInsetsListener(paywallView, null);
AdaptyPaywallInsets paywallInsets =
AdaptyPaywallInsets.of(systemBarInsets.top, 0);
paywallView.showPaywall(paywall, products, viewConfiguration, paywallInsets, productTitleResolver);
return insets;
});
```
## Utiliser une minuterie définie par le développeur \{#use-developer-defined-timer\}
Pour utiliser des minuteries définies par le développeur dans votre application mobile, créez un objet `timerResolver` — un dictionnaire ou une map qui associe des minuteries personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du paywall. Voici un exemple :
```kotlin showLineNumbers
...
val customTimers = mapOf(
"CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025
)
val timerResolver = AdaptyUiTimerResolver { timerId ->
customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } )
}
```
```java showLineNumbers
...
Map customTimers = new HashMap<>();
customTimers.put(
"CUSTOM_TIMER_NY",
new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime()
);
AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() {
@NonNull
@Override
public Date timerEndAtDate(@NonNull String timerId) {
Date date = customTimers.get(timerId);
return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */
}
};
```
Dans cet exemple, `CUSTOM_TIMER_NY` est le **Timer ID** de la minuterie définie par le développeur que vous avez configurée dans l'Adapty Dashboard. Le `timerResolver` garantit que votre application met dynamiquement à jour la minuterie avec la valeur correcte — par exemple `13d 09h 03m 34s` (calculée comme l'heure de fin de la minuterie, comme le Jour de l'An, moins l'heure actuelle).
## Utiliser des balises personnalisées \{#use-custom-tags\}
Pour utiliser des balises personnalisées dans votre application mobile, créez un objet `tagResolver` — un dictionnaire ou une map qui associe des balises personnalisées aux valeurs de chaîne qui les remplaceront lors du rendu du paywall. Voici un exemple :
```kotlin showLineNumbers
val customTags = mapOf("USERNAME" to "John")
val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] }
```
```java showLineNumbers
Map customTags = new HashMap<>();
customTags.put("USERNAME", "John");
AdaptyUiTagResolver tagResolver = customTags::get;
```
Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme ``. Le `tagResolver` garantit que votre application remplace dynamiquement cette balise personnalisée par la valeur spécifiée — par exemple `John`.
Nous recommandons de créer et de remplir le `tagResolver` juste avant de présenter votre paywall. Une fois prêt, passez-le à la méthode AdaptyUI que vous utilisez pour présenter le paywall.
## Modifier la couleur de l'indicateur de chargement du paywall \{#change-paywall-loading-indicator-color\}
Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante :
```xml showLineNumbers title = "XML"
```
---
# File: android-handle-paywall-actions
---
---
title: "Répondre aux actions des flows - Android"
description: "Gérez les actions des boutons des flows et paywalls dans votre app Android."
---
Si vous créez des flows ou des paywalls avec le Flow Builder ou le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons :
1. Ajoutez un [bouton dans le builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé.
2. Écrivez le code dans votre app pour gérer chaque action assignée.
Ce guide explique comment gérer les actions personnalisées et existantes dans votre code.
:::warning
**Seuls les achats, les restaurations, la fermeture des flows/paywalls et l'ouverture d'URL sont gérés automatiquement.** Toutes les autres actions de boutons nécessitent une implémentation appropriée dans le code de l'app.
:::
## Fermer les flows et les paywalls \{#close-flows-and-paywalls\}
Pour ajouter un bouton qui ferme votre flow ou paywall :
1. Dans le builder, ajoutez un bouton et assignez-lui l'action **Close**.
2. Dans le code de votre app, implémentez un handler pour l'action `close`.
:::info
Dans le SDK Android, l'action `close` déclenche par défaut la fermeture du flow ou du paywall. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un flow peut déclencher l'ouverture d'un autre.
:::
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior
}
}
```
## Ouvrir des URL depuis les flows et les paywalls \{#open-urls-from-flows-and-paywalls\}
:::tip
Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le builder et gérez-le de la même façon que les boutons avec l'action **Open URL**.
:::
Pour ajouter un bouton qui ouvre un lien depuis votre flow ou paywall (par exemple, **Terms of use** ou **Privacy policy**) :
1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir.
2. Dans le code de votre app, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur.
:::info
Dans le SDK Android, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire.
:::
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
is AdaptyUI.Action.OpenUrl -> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior
context.startActivity(intent)
}
}
}
```
## Gérer les actions personnalisées \{#handle-custom-actions\}
Pour ajouter un bouton qui gère d'autres actions :
1. Dans le builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID.
2. Dans le code de votre app, implémentez un handler pour l'ID d'action que vous avez créé.
Par exemple, si vous proposez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre flow ou paywall :
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
is AdaptyUI.Action.Custom -> {
if (action.customId == "openNewPaywall") {
// Display another flow or paywall
}
}
}
}
```
Si vous créez des paywalls avec le Paywall Builder d'Adapty, il est essentiel de configurer correctement les boutons :
1. Ajoutez un [bouton dans le Paywall Builder](paywall-buttons) et assignez-lui une action existante ou créez un ID d'action personnalisé.
2. Écrivez le code dans votre app pour gérer chaque action assignée.
Ce guide explique comment gérer les actions personnalisées et existantes dans votre code.
:::warning
**Seuls les achats, les restaurations, la fermeture des paywalls et l'ouverture d'URL sont gérés automatiquement.** Toutes les autres actions de boutons nécessitent une implémentation appropriée dans le code de l'app.
:::
## Fermer les paywalls \{#close-paywalls\}
Pour ajouter un bouton qui ferme votre paywall :
1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Close**.
2. Dans le code de votre app, implémentez un handler pour l'action `close` qui ferme le paywall.
:::info
Dans le SDK Android, l'action `close` déclenche par défaut la fermeture du paywall. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire. Par exemple, la fermeture d'un paywall peut déclencher l'ouverture d'un autre.
:::
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior
}
}
```
## Ouvrir des URL depuis les paywalls \{#open-urls-from-paywalls\}
:::tip
Si vous souhaitez ajouter un groupe de liens (par exemple, les conditions d'utilisation et la restauration des achats), ajoutez un élément **Link** dans le Paywall Builder et gérez-le de la même façon que les boutons avec l'action **Open URL**.
:::
Pour ajouter un bouton qui ouvre un lien depuis votre paywall (par exemple, **Terms of use** ou **Privacy policy**) :
1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Open URL** et saisissez l'URL à ouvrir.
2. Dans le code de votre app, implémentez un handler pour l'action `openUrl` qui ouvre l'URL reçue dans un navigateur.
:::info
Dans le SDK Android, l'action `openUrl` déclenche par défaut l'ouverture de l'URL. Vous pouvez toutefois redéfinir ce comportement dans votre code si nécessaire.
:::
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
is AdaptyUI.Action.OpenUrl -> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior
context.startActivity(intent)
}
}
}
```
## Se connecter à l'app \{#log-into-the-app\}
Pour ajouter un bouton qui connecte les utilisateurs à votre app :
1. Dans le Paywall Builder, ajoutez un bouton et assignez-lui l'action **Login**.
2. Dans le code de votre app, implémentez un handler pour l'action `login` qui identifie votre utilisateur.
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
AdaptyUI.Action.Login -> {
val intent = Intent(context, LoginActivity::class.java)
context.startActivity(intent)
}
}
}
```
## Gérer les actions personnalisées \{#handle-custom-actions\}
Pour ajouter un bouton qui gère d'autres actions :
1. Dans le Paywall Builder, ajoutez un bouton, assignez-lui l'action **Custom** et donnez-lui un ID.
2. Dans le code de votre app, implémentez un handler pour l'ID d'action que vous avez créé.
Par exemple, si vous proposez un autre ensemble d'offres d'abonnement ou d'achats uniques, vous pouvez ajouter un bouton qui affiche un autre paywall :
```kotlin
override fun onActionPerformed(action: AdaptyUI.Action, context: Context) {
when (action) {
is AdaptyUI.Action.Custom -> {
if (action.customId == "openNewPaywall") {
// Display another paywall
}
}
}
}
```
---
# File: android-handling-events
---
---
title: "Gérer les événements de flow et de paywall - Android"
description: "Gérez les événements de flow et de paywall dans votre application Android."
---
:::important
Ce guide couvre la gestion des événements liés aux achats, restaurations, sélections de produits et au rendu des flows. Vous devez également implémenter la gestion des boutons (fermeture du flow, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de boutons](android-handle-paywall-actions) pour plus de détails.
:::
Les flows et paywalls configurés avec le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut réagir. Ces événements incluent les pressions sur les boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats. Découvrez ci-dessous comment répondre à ces événements.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Si vous avez besoin de contrôler ou surveiller les processus qui se déroulent sur l'écran d'achat, implémentez les méthodes `AdaptyFlowEventListener`.
Si vous souhaitez conserver le comportement par défaut dans certains cas, vous pouvez étendre `AdaptyFlowDefaultEventListener` et ne remplacer que les méthodes que vous souhaitez modifier.
Voici les comportements par défaut de `AdaptyFlowDefaultEventListener`.
### Événements générés par l'utilisateur \{#user-generated-events\}
#### Sélection d'un produit \{#product-selection\}
Si un produit est sélectionné pour achat (par l'utilisateur ou par le système), cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onProductSelected(
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
#### Achat initié \{#started-purchase\}
Si un utilisateur lance le processus d'achat, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseStarted(
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\}
Si l'achat réussit, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseFinished(
purchaseResult: AdaptyPurchaseResult,
product: AdaptyPaywallProduct,
context: Context,
) {
if (purchaseResult !is AdaptyPurchaseResult.UserCanceled)
context.getActivityOrNull()?.onBackPressed()
}
```
Exemples d'événements (cliquer pour développer)
```javascript
// Successful purchase
{
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Cancelled purchase
{
"purchaseResult": {
"type": "UserCanceled"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Pending purchase
{
"purchaseResult": {
"type": "Pending"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
Nous recommandons de fermer l'écran dans ce cas.
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Achat échoué \{#failed-purchase\}
Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs Google Play Billing (restrictions de paiement, produits invalides, pannes réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `onPurchaseFinished` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode.
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseFailure(
error: AdaptyError,
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Navigation vers le paiement web terminée \{#finished-web-payment-navigation\}
Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées :
```kotlin showLineNumbers title="Kotlin"
public override fun onFinishWebPaymentNavigation(
product: AdaptyPaywallProduct?,
error: AdaptyError?,
context: Context,
) {}
```
**Paramètres :**
| Paramètre | Description |
|:------------|:-------------------------------------------------------------------------------------------------------------|
| **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. |
| **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. |
Exemples d'événements (cliquer pour développer)
```javascript
// Successful navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "web_navigation_failed",
"message": "Failed to open web paywall",
"details": {
"underlyingError": "Browser unavailable"
}
}
}
```
#### Restauration réussie \{#successful-restore\}
Si la restauration d'un achat réussit, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onRestoreSuccess(
profile: AdaptyProfile,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}
```
Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](android-listen-subscription-changes) pour savoir comment le vérifier.
#### Restauration échouée \{#failed-restore\}
Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onRestoreFailure(
error: AdaptyError,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}
```
#### Mise à niveau d'abonnement \{#upgrade-subscription\}
Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre est déjà actif, vous pouvez contrôler la façon dont le nouvel achat doit être géré en remplaçant cette méthode. Vous avez deux options :
1. **Remplacer l'abonnement actuel** par le nouveau :
```kotlin showLineNumbers title="Kotlin"
public override fun onAwaitingPurchaseParams(
product: AdaptyPaywallProduct,
context: Context,
onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback,
): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked {
onPurchaseParamsReceived(
AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...))
.build()
)
return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked
}
```
2. **Conserver les deux abonnements** (ajouter le nouveau séparément) :
```kotlin showLineNumbers title="Kotlin"
public override fun onAwaitingPurchaseParams(
product: AdaptyPaywallProduct,
context: Context,
onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback,
): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked {
onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty)
return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked
}
```
:::note
Si vous ne remplacez pas cette méthode, le comportement par défaut est de conserver les deux abonnements actifs (équivalent à utiliser `AdaptyPurchaseParameters.Empty`).
:::
Vous pouvez également définir des paramètres d'achat supplémentaires si nécessaire :
```kotlin
AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription
.withOfferPersonalized(true) // optional - if using personalized pricing
.build()
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_yearly",
"localizedTitle": "Premium Yearly",
"localizedDescription": "Premium subscription for 1 year",
"localizedPrice": "$99.99",
"price": 99.99,
"currencyCode": "USD"
},
"subscriptionUpdateParams": {
"replacementMode": "with_time_proration"
}
}
```
### Récupération de données et rendu \{#data-fetching-and-rendering\}
#### Erreurs de chargement des produits \{#product-loading-errors\}
Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode :
```kotlin showLineNumbers title="Kotlin"
public override fun onLoadingProductsFailure(
error: AdaptyError,
context: Context,
): Boolean = false
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}
```
Si vous retournez `true`, AdaptyUI relancera la requête dans 2 secondes.
#### Erreurs de rendu \{#rendering-errors\}
Si une erreur survient lors du rendu de l'interface, elle sera signalée en appelant cette méthode :
```kotlin showLineNumbers title="Kotlin"
public override fun onError(
error: AdaptyError,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "rendering_failed",
"message": "Failed to render flow interface",
"details": {
"underlyingError": "Invalid flow configuration"
}
}
}
```
Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le faire savoir.
### Navigation \{#navigation\}
#### Bouton retour système \{#system-back-button\}
Par défaut, un flow ne peut pas être fermé avec le bouton retour système ou le geste de retour — l'utilisateur le quitte via un chemin que vous définissez, comme un bouton **Fermer** ou une action `on_device_back` dans le builder. Si vous souhaitez que le bouton retour système ferme le flow, remplacez `onBackPressed` et retournez `false` pour laisser votre activité ou fragment hôte gérer l'appui :
```kotlin showLineNumbers title="Kotlin"
public override fun onBackPressed(context: Context): Boolean {
return false // let the host handle the back press (e.g. finish the activity or pop the fragment)
}
```
Ce callback n'est invoqué que lorsqu'aucune action `on_device_back` n'est configurée pour l'écran actuel — une action configurée prend la priorité et est gérée en interne. Retournez `true` pour consommer l'appui (comportement par défaut), ou `false` pour laisser la gestion du retour de l'hôte s'exécuter.
### Événements réservés \{#reserved-events\}
`AdaptyFlowEventListener` déclare quelques callbacks pour des fonctionnalités que les flows n'utilisent pas encore. Vous n'avez pas besoin de les implémenter — `AdaptyFlowDefaultEventListener` fournit déjà des implémentations vides par défaut.
| Méthode | Description |
|:--------|:------------|
| **onAnalyticEvent** | Réservé pour les événements analytiques personnalisés d'un flow. Les flows n'émettent pas encore ces événements vers votre code, vous n'avez donc pas besoin de l'implémenter. |
| **onShowAppRate** | Réservé pour les demandes d'évaluation d'application depuis un flow. Les flows ne déclenchent pas encore de demandes d'évaluation, vous n'avez donc pas besoin de l'implémenter. |
| **onShowRequestPermission** | Réservé pour les demandes d'autorisation système (comme les notifications push ou l'accès à la caméra) depuis un flow. Les flows ne déclenchent pas encore de demandes d'autorisation, vous n'avez donc pas besoin de l'implémenter. |
:::important
Ce guide couvre la gestion des événements liés aux achats, restaurations, sélections de produits et au rendu des paywalls. Vous devez également implémenter la gestion des boutons (fermeture du paywall, ouverture de liens, etc.). Consultez notre [guide sur la gestion des actions de boutons](android-handle-paywall-actions) pour plus de détails.
:::
Les paywalls configurés avec le [Paywall Builder](adapty-paywall-builder) n'ont pas besoin de code supplémentaire pour effectuer et restaurer des achats. Cependant, ils génèrent certains événements auxquels votre application peut réagir. Ces événements incluent les pressions sur les boutons (boutons de fermeture, URLs, sélections de produits, etc.) ainsi que des notifications sur les actions liées aux achats effectuées sur le paywall. Découvrez ci-dessous comment répondre à ces événements.
:::warning
Ce guide concerne uniquement les **nouveaux paywalls du Paywall Builder** qui nécessitent le SDK Adapty v3.0 ou une version ultérieure.
:::
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Si vous avez besoin de contrôler ou surveiller les processus qui se déroulent sur l'écran d'achat, implémentez les méthodes `AdaptyUiEventListener`.
Si vous souhaitez conserver le comportement par défaut dans certains cas, vous pouvez étendre `AdaptyUiDefaultEventListener` et ne remplacer que les méthodes que vous souhaitez modifier.
Voici les comportements par défaut de `AdaptyUiDefaultEventListener`.
### Événements générés par l'utilisateur \{#user-generated-events\}
#### Sélection d'un produit \{#product-selection\}
Si un produit est sélectionné pour achat (par l'utilisateur ou par le système), cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onProductSelected(
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
#### Achat initié \{#started-purchase\}
Si un utilisateur lance le processus d'achat, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseStarted(
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Achat réussi, annulé ou en attente \{#successful-canceled-or-pending-purchase\}
Si l'achat réussit, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseFinished(
purchaseResult: AdaptyPurchaseResult,
product: AdaptyPaywallProduct,
context: Context,
) {
if (purchaseResult !is AdaptyPurchaseResult.UserCanceled)
context.getActivityOrNull()?.onBackPressed()
}
```
Exemples d'événements (cliquer pour développer)
```javascript
// Successful purchase
{
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Cancelled purchase
{
"purchaseResult": {
"type": "UserCanceled"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
// Pending purchase
{
"purchaseResult": {
"type": "Pending"
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
Nous recommandons de fermer l'écran dans ce cas.
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Achat échoué \{#failed-purchase\}
Si un achat échoue en raison d'une erreur, cette méthode sera invoquée. Cela inclut les erreurs Google Play Billing (restrictions de paiement, produits invalides, pannes réseau), les échecs de vérification de transaction et les erreurs système. Notez que les annulations par l'utilisateur déclenchent `onPurchaseFinished` avec un résultat annulé, et les paiements en attente ne déclenchent pas cette méthode.
```kotlin showLineNumbers title="Kotlin"
public override fun onPurchaseFailure(
error: AdaptyError,
product: AdaptyPaywallProduct,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
},
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}
```
La méthode ne sera pas invoquée en mode Observer. Consultez la rubrique [Android - Afficher les paywalls du Paywall Builder en mode Observer](android-present-paywall-builder-paywalls-in-observer-mode) pour plus de détails.
#### Navigation vers le paiement web terminée \{#finished-web-payment-navigation\}
Cette méthode est invoquée après une tentative d'ouverture d'un [paywall web](web-paywall) pour un produit spécifique. Cela inclut les tentatives de navigation réussies et échouées :
```kotlin showLineNumbers title="Kotlin"
public override fun onFinishWebPaymentNavigation(
product: AdaptyPaywallProduct?,
error: AdaptyError?,
context: Context,
) {}
```
**Paramètres :**
| Paramètre | Description |
|:------------|:-------------------------------------------------------------------------------------------------------------|
| **product** | Un `AdaptyPaywallProduct` pour lequel le paywall web a été ouvert. Peut être `null`. |
| **error** | Un objet `AdaptyError` si la navigation vers le paywall web a échoué ; `null` si la navigation a réussi. |
Exemples d'événements (cliquer pour développer)
```javascript
// Successful navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "web_navigation_failed",
"message": "Failed to open web paywall",
"details": {
"underlyingError": "Browser unavailable"
}
}
}
```
#### Restauration réussie \{#successful-restore\}
Si la restauration d'un achat réussit, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onRestoreSuccess(
profile: AdaptyProfile,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}
```
Nous recommandons de fermer l'écran si l'utilisateur possède le `accessLevel` requis. Consultez la rubrique [Statut de l'abonnement](android-listen-subscription-changes) pour savoir comment le vérifier.
#### Restauration échouée \{#failed-restore\}
Si `Adapty.restorePurchases()` échoue, cette méthode sera invoquée :
```kotlin showLineNumbers title="Kotlin"
public override fun onRestoreFailure(
error: AdaptyError,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}
```
#### Mise à niveau d'abonnement \{#upgrade-subscription\}
Lorsqu'un utilisateur tente d'acheter un nouvel abonnement alors qu'un autre est déjà actif, vous pouvez contrôler la façon dont le nouvel achat doit être géré en remplaçant cette méthode. Vous avez deux options :
1. **Remplacer l'abonnement actuel** par le nouveau :
```kotlin showLineNumbers title="Kotlin"
public override fun onAwaitingPurchaseParams(
product: AdaptyPaywallProduct,
context: Context,
onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback,
): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked {
onPurchaseParamsReceived(
AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...))
.build()
)
return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked
}
```
2. **Conserver les deux abonnements** (ajouter le nouveau séparément) :
```kotlin showLineNumbers title="Kotlin"
public override fun onAwaitingPurchaseParams(
product: AdaptyPaywallProduct,
context: Context,
onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback,
): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked {
onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty)
return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked
}
```
:::note
Si vous ne remplacez pas cette méthode, le comportement par défaut est de conserver les deux abonnements actifs (équivalent à utiliser `AdaptyPurchaseParameters.Empty`).
:::
Vous pouvez également définir des paramètres d'achat supplémentaires si nécessaire :
```kotlin
AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription
.withOfferPersonalized(true) // optional - if using personalized pricing
.build()
```
Si un nouvel abonnement est acheté alors qu'un autre est encore actif, remplacez cette méthode pour substituer l'abonnement actuel par le nouveau. Si l'abonnement actif doit rester actif et que le nouveau est ajouté séparément, appelez `onSubscriptionUpdateParamsReceived(null)` :
```kotlin showLineNumbers title="Kotlin"
public override fun onAwaitingSubscriptionUpdateParams(
product: AdaptyPaywallProduct,
context: Context,
onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback,
) {
onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...))
}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"product": {
"vendorProductId": "premium_yearly",
"localizedTitle": "Premium Yearly",
"localizedDescription": "Premium subscription for 1 year",
"localizedPrice": "$99.99",
"price": 99.99,
"currencyCode": "USD"
},
"subscriptionUpdateParams": {
"replacementMode": "with_time_proration"
}
}
```
### Récupération de données et rendu \{#data-fetching-and-rendering\}
#### Erreurs de chargement des produits \{#product-loading-errors\}
Si vous ne transmettez pas les produits lors de l'initialisation, AdaptyUI récupérera les objets nécessaires depuis le serveur par lui-même. Si cette opération échoue, AdaptyUI signalera l'erreur en invoquant cette méthode :
```kotlin showLineNumbers title="Kotlin"
public override fun onLoadingProductsFailure(
error: AdaptyError,
context: Context,
): Boolean = false
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}
```
Si vous retournez `true`, AdaptyUI relancera la requête dans 2 secondes.
#### Erreurs de rendu \{#rendering-errors\}
Si une erreur survient lors du rendu de l'interface, elle sera signalée en appelant cette méthode :
```kotlin showLineNumbers title="Kotlin"
public override fun onRenderingError(
error: AdaptyError,
context: Context,
) {}
```
Exemple d'événement (cliquer pour développer)
```javascript
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
}
```
Dans une situation normale, de telles erreurs ne devraient pas se produire, donc si vous en rencontrez une, veuillez nous le faire savoir.
---
# File: android-use-fallback-paywalls
---
---
title: "Android - Utiliser les paywalls de secours"
description: "Gérez les cas où les utilisateurs sont hors ligne ou les serveurs Adapty ne sont pas disponibles."
---
:::warning
Les paywalls de secours sont pris en charge par le SDK Android v2.11 et versions ultérieures.
:::
To maintain a fluid user experience, it is important to set up [fallbacks](/fallback-paywalls) for your flows, [paywalls](paywalls), and [onboardings](onboardings). This precaution extends the application's capabilities in case of partial or complete loss of internet connection.
* **If the application cannot access Adapty servers:**
It will be able to display a fallback flow or paywall, and access the local onboarding configuration.
* **If the application cannot access the internet:**
It will be able to display a fallback flow or paywall. Onboardings include remote content and require an internet connection to function.
:::important
Before you follow the steps in this guide, [download](/local-fallback-paywalls) the fallback configuration files from Adapty.
:::
## Configuration \{#configuration\}
1. Déplacez le fichier de configuration de secours dans le répertoire `assets` ou `res/raw` de votre projet Android.
2. Appelez la méthode `.setFallback` **avant** de récupérer le flow, le paywall ou l'onboarding cible.
```kotlin showLineNumbers
//if you put the 'android_fallback.json' file to the 'assets' directory
val location = FileLocation.fromAsset("android_fallback.json")
//or `FileLocation.fromAsset("/android_fallback.json")` if you placed it in a child folder of 'assets')
//if you put the 'android_fallback.json' file to the 'res/raw' directory
val location = FileLocation.fromResId(context, R.raw.android_fallback)
//you can also pass a file URI
val fileUri: Uri = //get Uri for the file with fallback paywalls
val location = FileLocation.fromFileUri(fileUri)
//pass the file location
Adapty.setFallback(location, callback)
```
```java showLineNumbers
//if you put the 'android_fallback.json' file to the 'assets' directory
FileLocation location = FileLocation.fromAsset("android_fallback.json");
//or `FileLocation.fromAsset("/android_fallback.json");` if you placed it in a child folder of 'assets')
//if you put the 'android_fallback.json' file to the 'res/raw' directory
FileLocation location = FileLocation.fromResId(context, R.raw.android_fallback);
//you can also pass a file URI
Uri fileUri = //get Uri for the file with fallback paywalls
FileLocation location = FileLocation.fromFileUri(fileUri);
//pass the file location
Adapty.setFallback(location, callback);
```
Paramètres :
| Paramètre | Description |
| :----------- | :----------------------------------------------------------- |
| **location** | L'objet [FileLocation](https://android.adapty.io/adapty/com.adapty.utils/-file-location/-companion/) pour le fichier de configuration de secours |
---
# File: android-localizations-and-locale-codes
---
---
title: "Utiliser les localisations et codes de locale dans le SDK Android"
description: "Gérez les localisations et codes de locale de votre application pour toucher une audience mondiale (Android)."
---
## Pourquoi c'est important \{#why-this-is-important\}
Les codes de langue entrent en jeu quand Adapty choisit la localisation pour un flow, et quand vous lisez un Remote Config pour un paywall personnalisé.
Les codes de langue sont complexes et peuvent varier d'une plateforme à l'autre. Adapty s'appuie donc sur un standard interne unique pour toutes les plateformes qu'il prend en charge. Comprendre ce standard vous permet de prédire quelle localisation un utilisateur recevra.
## Standard des codes de langue chez Adapty \{#locale-code-standard-at-adapty\}
Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-étiquettes en minuscules, séparées par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel).
## Correspondance des codes de langue \{#locale-code-matching\}
Lorsqu'Adapty recherche la localisation correspondant à la locale d'un utilisateur, voici ce qui se passe :
1. La chaîne de locale est convertie en minuscules et tous les tirets bas (`_`) sont remplacés par des tirets (`-`)
2. Adapty recherche la localisation dont le code de locale correspond exactement
3. Si aucune correspondance n'est trouvée, Adapty extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et recherche la localisation correspondante
4. Si aucune correspondance n'est trouvée à nouveau, Adapty renvoie le contenu dans la langue par défaut du flow
Cette façon de procéder permet à `'pt_BR'`, `pt-BR` et `pt-br` de pointer vers la même localisation.
## Implémentation des localisations \{#implementing-localizations\}
Dans le SDK v4, vous ne transmettez pas de code de langue lors de la récupération d'un flow — `getFlow` retourne le flow avec toutes ses localisations.
- **Flows créés dans le builder** : le SDK ne lit pas la locale de l'appareil, vous devez donc la résoudre dans votre application et la passer comme argument `locale` de `AdaptyUI.getFlowConfiguration`. L'argument est optionnel — omettez-le et le flow s'affiche en `en`, ou dans sa [locale par défaut](add-paywall-locale-in-adapty-paywall-builder#set-the-default-locale) si le flow n'a pas de localisation `en`. Si vous demandez une localisation que le flow ne possède pas, la vue revient à la valeur par défaut du flow sans erreur, et les chaînes manquantes dans la localisation choisie sont reprises de la locale par défaut.
Le rendu en `en` par défaut nécessite le SDK Android 4.0.1. Dans la version 4.0.0, l'omission de `locale` affiche la localisation par défaut du flow.
- **Paywalls personnalisés (Remote Config)** : `getFlow` retourne toutes les localisations configurées dans `flow.remoteConfigs`. Chaque entrée contient un code `locale` et le contenu de la configuration (`jsonString`, ou le `dataMap` parsé). Sélectionnez l'entrée correspondant à l'utilisateur, avec votre propre logique de repli :
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
?: flow.remoteConfigs.firstOrNull()
// read your values from config?.dataMap
}
is AdaptyResult.Error -> {
// handle the error
}
}
}
```
Les règles de correspondance des codes de paramètres régionaux décrites ci-dessus expliquent comment Adapty normalise les codes `locale` stockés dans chaque Remote Config.
## Pourquoi c'est important \{#why-this-is-important\}
Il existe plusieurs situations où les codes de langue entrent en jeu — par exemple, lorsque vous essayez de récupérer le bon paywall pour la localisation actuelle de votre application.
Les codes de langue étant complexes et pouvant varier d'une plateforme à l'autre, nous nous appuyons sur un standard interne pour toutes les plateformes que nous prenons en charge. Cependant, en raison de cette complexité, il est vraiment important que vous compreniez exactement ce que vous envoyez à notre serveur pour obtenir la bonne localisation, et ce qui se passe ensuite — afin que vous receviez toujours ce que vous attendez.
## Standard de code de langue chez Adapty \{#locale-code-standard-at-adapty\}
Pour les codes de langue, Adapty utilise une version légèrement modifiée du [standard BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) : chaque code est composé de sous-tags en minuscules, séparés par des tirets. Quelques exemples : `en` (anglais), `pt-br` (portugais (Brésil)), `zh` (chinois simplifié), `zh-hant` (chinois traditionnel).
## Correspondance des codes de langue \{#locale-code-matching\}
Quand Adapty reçoit un appel du SDK côté client avec un code de langue et commence à chercher la localisation correspondante d'un paywall, voici ce qui se passe :
1. La chaîne de locale reçue est convertie en minuscules et tous les underscores (`_`) sont remplacés par des tirets (`-`)
2. On cherche ensuite la localisation dont le code de locale correspond exactement
3. Si aucune correspondance n'est trouvée, on extrait la sous-chaîne avant le premier tiret (`pt` pour `pt-br`) et on cherche la localisation correspondante
4. Si aucune correspondance n'est trouvée non plus, on renvoie le contenu dans la locale par défaut du paywall
Ainsi, un appareil iOS qui a envoyé `'pt_BR'`, un appareil Android qui a envoyé `pt-BR`, et un autre appareil qui a envoyé `pt-br` obtiendront le même résultat.
## Mise en œuvre des localisations : méthode recommandée \{#implementing-localizations-recommended-way\}
Si vous vous interrogez sur les localisations, vous travaillez probablement déjà avec des fichiers de chaînes localisées dans votre projet. Dans ce cas, nous vous recommandons d'ajouter une paire clé-valeur avec le code de locale Adapty correspondant dans chacun de vos fichiers de localisation. Ensuite, récupérez la valeur de cette clé lors de l'appel à notre SDK, comme ceci :
```kotlin showLineNumbers
// 1. Modify your strings.xml files
/*
strings.xml - Spanish
*/
es
/*
strings.xml - Portuguese (Brazil)
*/
pt-br
// 2. Extract and use the locale code
val localeCode = context.getString(R.string.adapty_paywalls_locale)
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method
```
Vous contrôlez ainsi entièrement la localisation qui sera récupérée pour chaque utilisateur de votre application.
## Implémenter les localisations : l'autre méthode \{#implementing-localizations-the-other-way\}
Vous pouvez obtenir des résultats similaires (mais pas identiques) sans définir explicitement les codes de langue pour chaque localisation. Il s'agirait d'extraire un code de langue depuis d'autres objets fournis par votre plateforme, comme ceci :
```kotlin showLineNumbers
val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
context.resources.configuration.locales[0]
else
context.resources.configuration.locale
val localeCode = locale.toLanguageTag()
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method
```
Notez que nous ne recommandons pas cette approche car il est difficile de prévoir exactement ce que le serveur d'Adapty recevra.
Si vous décidez tout de même d'utiliser cette approche, assurez-vous d'avoir couvert tous les cas d'utilisation pertinents.
---
# File: android-web-paywall
---
---
title: "Implémenter les paywalls web dans le SDK Android"
description: "Configurez un paywall web pour accepter des paiements sans les frais et audits du Play Store."
---
:::important
Avant de commencer, assurez-vous d'avoir [configuré votre paywall web dans le tableau de bord](web-paywall) et d'avoir installé la version 3.15 ou ultérieure du SDK Adapty.
:::
## Ouvrir les paywalls web \{#open-web-paywalls\}
Si vous travaillez avec un paywall que vous avez développé vous-même, vous devez gérer les paywalls web via la méthode du SDK. La méthode `.openWebPaywall` :
1. Génère une URL unique permettant à Adapty de relier un paywall spécifique affiché à un utilisateur particulier à la page web vers laquelle il est redirigé.
2. Détecte quand vos utilisateurs reviennent dans l'application, puis appelle `.getProfile` à intervalles rapprochés pour déterminer si les droits d'accès du profil ont été mis à jour.
Ainsi, si le paiement a réussi et que les droits d'accès ont été mis à jour, l'abonnement s'active dans l'application presque immédiatement.
:::note
Après le retour des utilisateurs dans l'application, actualisez l'interface pour refléter les mises à jour du profil. Adapty recevra et traitera les événements de mise à jour du profil.
:::
```kotlin showLineNumbers
Adapty.openWebPaywall(
activity = activity,
product = product,
) { error ->
if (error == null) {
// the web paywall was opened successfully
} else {
// handle the error
}
}
```
:::note
Il existe deux versions de la méthode `openWebPaywall` :
1. `openWebPaywall(product)` qui génère des URL par paywall et ajoute également les données du produit aux URL.
2. `openWebPaywall(paywall)` qui génère des URL par paywall sans ajouter les données du produit aux URL. Utilisez-la quand vos produits dans le paywall Adapty diffèrent de ceux du paywall web.
:::
## Ouvrir les paywalls web dans un navigateur intégré \{#open-web-paywalls-in-an-in-app-browser\}
Par défaut, les paywalls web s'ouvrent dans le navigateur externe.
Pour offrir une expérience utilisateur fluide, vous pouvez ouvrir les paywalls web dans un navigateur intégré. La page d'achat web s'affiche alors directement dans votre application, permettant aux utilisateurs de finaliser leurs transactions sans changer d'application.
Pour activer cette option, définissez le paramètre `presentation` sur `AdaptyWebPresentation.InAppBrowser` :
```kotlin showLineNumbers
Adapty.openWebPaywall(
activity = activity,
product = product,
presentation = AdaptyWebPresentation.InAppBrowser,
) { error ->
if (error == null) {
// the web paywall was opened successfully
} else {
// handle the error
val adaptyError = error
}
}
```
---
# File: android-troubleshoot-paywall-builder
---
---
title: "Dépanner le Paywall Builder dans le SDK Android"
description: "Dépanner le Paywall Builder dans le SDK Android"
---
Ce guide vous aide à résoudre les problèmes courants lors de l'utilisation de paywalls conçus dans le Paywall Builder d'Adapty avec le SDK Android.
## La récupération de la configuration du paywall échoue \{#getting-a-paywall-configuration-fails\}
**Problème** : La méthode `getViewConfiguration` ne parvient pas à récupérer la configuration du paywall.
**Cause** : Le paywall n'est pas activé pour l'affichage sur l'appareil dans le Paywall Builder.
**Solution** : Activez le bouton **Show on device** dans le Paywall Builder.
## Le nombre de vues du paywall est trop élevé \{#the-paywall-view-number-is-too-big\}
**Problème** : Le compteur de vues du paywall affiche le double du nombre attendu.
**Cause** : Vous appelez peut-être `logShowFlow` (SDK Android v4+) / `logShowPaywall` dans votre code, ce qui double le compteur de vues si vous utilisez le Paywall Builder ou le Flow Builder. Pour les flows et les paywalls construits avec ces outils, l'analytique est suivie automatiquement, il n'est donc pas nécessaire d'utiliser cette méthode.
**Solution** : Assurez-vous de ne pas appeler `logShowFlow` (SDK Android v4+) / `logShowPaywall` dans votre code si vous utilisez le Paywall Builder ou le Flow Builder.
## Autres problèmes \{#other-issues\}
**Problème** : Vous rencontrez d'autres problèmes liés au Paywall Builder non couverts ci-dessus.
**Solution** : Migrez le SDK vers la dernière version en utilisant les [guides de migration](android-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK.
---
# File: android-implement-paywalls-manually
---
---
title: "Implémenter les paywalls manuellement dans le SDK Android"
description: "Découvrez comment implémenter des paywalls manuellement dans votre application Android avec le SDK Adapty."
---
## Accepter les achats \{#accept-purchases\}
Si vous travaillez avec des paywalls que vous avez implémentés vous-même, vous pouvez déléguer la gestion des achats à Adapty en utilisant la méthode `makePurchase`. De cette façon, nous gérons tous les scénarios utilisateur, et vous n'avez qu'à traiter les résultats de l'achat.
:::important
`makePurchase` fonctionne avec les produits créés dans l'Adapty Dashboard. Assurez-vous de configurer les produits et les moyens de les récupérer dans le tableau de bord en suivant le [guide de démarrage rapide](quickstart).
:::
## Mode observateur \{#observer-mode\}
Si vous souhaitez implémenter votre propre logique de gestion des achats de A à Z, tout en bénéficiant des analyses avancées d'Adapty, vous pouvez utiliser le mode observateur.
:::important
Consultez les limitations du mode observateur [ici](observer-vs-full-mode).
:::
---
# File: android-quickstart-manual
---
---
title: "Activer les achats dans votre paywall personnalisé avec le SDK Android"
description: "Intégrez le SDK Adapty dans vos paywalls Android personnalisés pour activer les achats intégrés."
---
Ce guide explique comment intégrer Adapty dans vos paywalls personnalisés. Gardez le contrôle total sur l'implémentation du paywall, pendant que le SDK Adapty récupère les produits, gère les nouveaux achats et restaure les achats précédents.
:::important
**Ce guide s'adresse aux développeurs qui implémentent des paywalls personnalisés.** Si vous souhaitez la méthode la plus simple pour activer les achats, utilisez le [Adapty Flow Builder](android-quickstart-paywalls). Avec Flow Builder, vous créez des flows dans un éditeur visuel sans code, Adapty gère toute la logique d'achat automatiquement, et vous pouvez tester différents designs sans republier votre application.
:::
## Avant de commencer \{#before-you-start\}
### Configurer les produits \{#set-up-products\}
Pour activer les achats intégrés, vous devez comprendre trois concepts clés :
- [**Produits**](product) – tout ce que les utilisateurs peuvent acheter (abonnements, consommables, accès à vie)
- [**Paywalls**](paywalls) – configurations qui définissent quels produits proposer. Dans Adapty, les paywalls sont le seul moyen de récupérer des produits, mais cette conception vous permet de modifier les produits, les prix et les offres sans toucher au code de votre application.
- [**Placements**](placements) – où et quand vous affichez les paywalls dans votre application (comme `main`, `onboarding`, `settings`). Vous configurez les paywalls pour les placements dans le tableau de bord, puis vous les demandez par ID de placement dans votre code. Cela facilite la mise en place de tests A/B et l'affichage de différents paywalls à différents utilisateurs.
Assurez-vous de comprendre ces concepts même si vous travaillez avec votre paywall personnalisé. Ils constituent simplement votre façon de gérer les produits que vous vendez dans votre application.
Pour implémenter votre paywall personnalisé, vous devrez créer un **paywall** et l'ajouter à un **placement**. Cette configuration vous permet de récupérer vos produits. Pour comprendre ce que vous devez faire dans le tableau de bord, suivez le guide de démarrage rapide [ici](quickstart).
### Gérer les utilisateurs \{#manage-users\}
Vous pouvez travailler avec ou sans authentification backend de votre côté.
Cependant, le SDK Adapty gère différemment les utilisateurs anonymes et identifiés. Lisez le [guide de démarrage rapide sur l'identification](android-quickstart-identify) pour comprendre les spécificités et vous assurer de travailler correctement avec les utilisateurs.
## Étape 1. Récupérer les produits \{#step-1-get-products\}
Pour récupérer les produits de votre paywall personnalisé, vous devez :
1. Obtenir l'objet `flow` en passant l'ID du [placement](placements) à la méthode `getFlow`.
2. Obtenir le tableau de produits pour ce flow en utilisant la méthode `getPaywallProducts`.
```kotlin showLineNumbers
fun loadPaywall() {
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
Adapty.getPaywallProducts(flow) { productResult ->
when (productResult) {
is AdaptyResult.Success -> {
val products = productResult.value
// Use products to build your custom paywall UI
}
is AdaptyResult.Error -> {
val error = productResult.error
// Handle the error
}
}
}
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
}
```
```java showLineNumbers
public void loadPaywall() {
Adapty.getFlow("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
Adapty.getPaywallProducts(flow, productResult -> {
if (productResult instanceof AdaptyResult.Success) {
List products = ((AdaptyResult.Success>) productResult).getValue();
// Use products to build your custom paywall UI
} else if (productResult instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) productResult).getError();
// Handle the error
}
});
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle the error
}
});
}
```
## Étape 2. Accepter les achats \{#step-2-accept-purchases\}
Lorsqu'un utilisateur appuie sur un produit dans votre paywall personnalisé, appelez la méthode `makePurchase` avec le produit sélectionné. Cela gérera le flux d'achat et retournera le profil mis à jour.
```kotlin showLineNumbers
fun purchaseProduct(activity: Activity, product: AdaptyPaywallProduct) {
Adapty.makePurchase(activity, product) { result ->
when (result) {
is AdaptyResult.Success -> {
when (val purchaseResult = result.value) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
// Purchase successful, profile updated
}
is AdaptyPurchaseResult.UserCanceled -> {
// User canceled the purchase
}
is AdaptyPurchaseResult.Pending -> {
// Purchase is pending (e.g., user will pay offline with cash)
}
}
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
}
```
```java showLineNumbers
public void purchaseProduct(Activity activity, AdaptyPaywallProduct product) {
Adapty.makePurchase(activity, product, null, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue();
if (purchaseResult instanceof AdaptyPurchaseResult.Success) {
AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile();
// Purchase successful, profile updated
} else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) {
// User canceled the purchase
} else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) {
// Purchase is pending (e.g., user will pay offline with cash)
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle the error
}
});
}
```
## Étape 3. Restaurer les achats \{#step-3-restore-purchases\}
Google Play et les autres stores d'applications exigent que toutes les applications proposant des abonnements offrent un moyen aux utilisateurs de restaurer leurs achats.
Appelez la méthode `restorePurchases` lorsque l'utilisateur appuie sur le bouton de restauration. Cela synchronisera son historique d'achats avec Adapty et retournera le profil mis à jour.
```kotlin showLineNumbers
fun restorePurchases() {
Adapty.restorePurchases { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
// Restore successful, profile updated
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
}
```
```java showLineNumbers
public void restorePurchases() {
Adapty.restorePurchases(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
// Restore successful, profile updated
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle the error
}
});
}
```
## Étapes suivantes \{#next-steps\}
:::tip
Des questions ou des problèmes ? Consultez notre [forum d'assistance](https://adapty.featurebase.app/) où vous trouverez des réponses aux questions fréquentes ou pourrez poser les vôtres. Notre équipe et notre communauté sont là pour vous aider !
:::
Votre paywall est prêt à être affiché dans l'application. [Testez vos achats sur Google Play Store](testing-on-android) pour vous assurer de pouvoir effectuer un achat test depuis le paywall. Pour voir comment cela fonctionne dans une implémentation prête pour la production, consultez le [ProductListFragment.kt](https://github.com/adaptyteam/AdaptySDK-Android/blob/master/app/src/main/java/com/adapty/example/ProductListFragment.kt) dans notre exemple d'application, qui illustre la gestion des achats avec une gestion des erreurs appropriée, des retours d'interface utilisateur et la gestion des abonnements.
Ensuite, [vérifiez si les utilisateurs ont finalisé leur achat](android-check-subscription-status) pour déterminer si vous devez afficher le paywall ou accorder l'accès aux fonctionnalités payantes.
---
# File: fetch-paywalls-and-products-android
---
---
title: "Récupérer les paywalls et produits pour les paywalls de Remote Config dans le SDK Android"
description: "Récupérez les paywalls et produits dans le SDK Android Adapty pour améliorer la monétisation des utilisateurs."
---
Avant d'afficher un Remote Config ou des paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne les Remote Config et les paywalls personnalisés. Pour récupérer des flows ou des paywalls personnalisés dans le **Flow Builder** ou le **Paywall Builder**, consultez [Obtenir des flows et des paywalls](android-get-pb-paywalls).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à récupérer les flows et les produits dans votre application mobile (cliquez pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un flow ou un paywall et intégrez-y les produits](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez votre flow ou paywall dans le placement](create-placement) dans l'Adapty Dashboard.
4. [Installez le SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer les informations d'un flow \{#fetch-flow-information\}
Dans Adapty, un [produit](product) est une combinaison de produits issus de l'App Store et de Google Play. Ces produits multi-plateformes sont intégrés dans des flows et des paywalls, ce qui vous permet de les présenter dans des placements spécifiques de votre application mobile.
Pour afficher les produits, vous devez obtenir un `AdaptyFlow` depuis l'un de vos [placements](placements) à l'aide de la méthode `getFlow`.
:::important
**N'écrivez pas les identifiants de produits en dur dans le code.** Le seul identifiant à coder en dur est celui du placement. Les flows sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements de manière dynamique — si un flow renvoie deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code.
:::
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
// the requested flow
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
// the requested flow
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. || **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données mises en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs disposent toujours des données les plus récentes.
Toutefois, si vous pensez que vos utilisateurs sont souvent confrontés à une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données mises en cache si elles existent. Dans ce cas, les utilisateurs n'auront peut-être pas accès aux toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui le rend fiable pendant la session pour éviter des requêtes réseau inutiles.
Notez que le cache est conservé après le redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou d'un nettoyage manuel.
Le SDK Adapty stocke les flows et les paywalls en deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](android-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les flows et les paywalls plus rapidement, ainsi qu'un serveur de secours autonome au cas où le CDN serait inaccessible.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'attente pour cette méthode. Si le délai est atteint, les données mises en cache ou le fallback local sont renvoyés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut regrouper différentes requêtes en arrière-plan.
|
N'encodez pas les IDs de produit en dur ! Comme les flows sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent changer à tout moment. Assurez-vous que votre code gère ces scénarios.
Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à encoder en dur est l'ID de placement.
Paramètres de la réponse :
| Paramètre | Description |
| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Flow | Un objet `AdaptyFlow` contenant le placement, les identifiants (`id`, `variationId`), le nom, un tableau `remoteConfigs` (une entrée par locale configurée) et un indicateur `hasViewConfiguration`. Pour récupérer les produits du flow, appelez `getPaywallProducts(flow)`. |
:::note
Dans la v4, le paramètre `locale` a été déplacé hors de `getFlow` et dans `getFlowConfiguration` (utilisé uniquement lors du rendu avec AdaptyUI). Pour les paywalls personnalisés, toutes les locales disponibles sont renvoyées ensemble dans `flow.remoteConfigs` — choisissez la locale qui correspond à la langue de l'appareil de l'utilisateur ou au paramètre de votre application.
:::
## Récupérer les produits \{#fetch-products\}
Une fois que vous avez le flow, vous pouvez récupérer le tableau de produits qui lui correspond :
```kotlin showLineNumbers
Adapty.getPaywallProducts(flow) { result ->
when (result) {
is AdaptyResult.Success -> {
val products = result.value
// the requested products
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywallProducts(flow, result -> {
if (result instanceof AdaptyResult.Success) {
List products = ((AdaptyResult.Success>) result).getValue();
// the requested products
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Products | Liste d'objets [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) contenant : l'identifiant du produit, son nom, son prix, la devise, la durée de l'abonnement et plusieurs autres propriétés. |
Lorsque vous implémentez votre propre design de flow, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir des détails complets sur toutes les propriétés disponibles.
| Propriété | Description |
|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la locale de l'appareil. |
| **Price** | Pour afficher le prix dans sa version localisée, utilisez `product.price.localizedString`. La localisation est basée sur les informations de locale de l'appareil. Vous pouvez également accéder au prix sous forme de nombre via `product.price.amount`. La valeur sera fournie dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. |
| **Subscription Period** | Pour afficher la période (ex. : semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. La localisation est basée sur la locale de l'appareil. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez alors accéder à l'enum `unit` pour obtenir la durée (c.-à-d. DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` vous donnera le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, vous verrez `MONTH` dans la propriété unit et `3` dans la propriété numberOfUnits. |
| **Introductory Offer** | Pour afficher un badge ou un autre indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase contient les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.
• `price` : le prix réduit sous forme de nombre. Pour les essais gratuits, attendez-vous à voir `0` ici.
• `localizedNumberOfPeriods` : une chaîne localisée selon la locale de l'appareil, décrivant la durée de l'offre. Par exemple, une offre d'essai de trois jours affiche `3 days` dans ce champ.
• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période d'offre avec cette propriété. Elle fonctionne de la même manière pour les offres que dans la section précédente.
• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon la locale de l'utilisateur. |
## Accélérer la récupération des flows avec un flow d'audience par défaut \{#speed-up-flow-fetching-with-default-audience-flow\}
En général, les flows sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et placements, et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un flow peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un flow par défaut pour garantir une expérience fluide plutôt que de ne rien afficher du tout.
Pour remédier à cela, vous pouvez utiliser la méthode `getFlowForDefaultAudience`, qui récupère le flow du placement spécifié pour l'audience **All Users**. Cependant, il est crucial de comprendre que l'approche recommandée est de récupérer le flow via la méthode `getFlow`, comme décrit dans la section [Récupérer les informations du flow](fetch-paywalls-and-products-android#fetch-flow-information) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getFlow`
La méthode `getFlowForDefaultAudience` présente quelques inconvénients importants :
- **Problèmes potentiels de compatibilité ascendante** : Si vous devez afficher des flows différents selon les versions de l'application (actuelle et future), vous risquez de rencontrer des difficultés. Vous devrez soit concevoir des flows compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent rencontrer des problèmes avec des flows qui ne s'affichent pas correctement.
- **Perte de ciblage** : Tous les utilisateurs verront le même flow conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (notamment selon les pays, l'attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide du flow, utilisez la méthode `getFlowForDefaultAudience` comme suit. Sinon, restez sur le `getFlow` décrit [ci-dessus](fetch-paywalls-and-products-android#fetch-flow-information).
:::
```kotlin showLineNumbers
Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
// the requested flow
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
// le flow demandé
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// gérer l'erreur
}
});
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | obligatoire | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. || **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sûr de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la désinstallation de l'application ou via un nettoyage manuel.
|
Avant de présenter les Remote Config et les paywalls personnalisés, vous devez récupérer les informations les concernant. Notez que cette rubrique concerne les Remote Config et les paywalls personnalisés. Pour obtenir des instructions sur la récupération des paywalls créés avec le Paywall Builder, consultez [Récupérer les paywalls du Paywall Builder et leur configuration](android-get-pb-paywalls).
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
Avant de commencer à récupérer les paywalls et les produits dans votre application mobile (cliquez pour développer)
1. [Créez vos produits](create-product) dans l'Adapty Dashboard.
2. [Créez un paywall et intégrez les produits dans votre paywall](create-paywall) dans l'Adapty Dashboard.
3. [Créez des placements et intégrez votre paywall dans le placement](create-placement) dans l'Adapty Dashboard.
4. [Installez le SDK Adapty](sdk-installation-android) dans votre application mobile.
## Récupérer les informations du paywall \{#fetch-paywall-information\}
Dans Adapty, un [produit](product) est une combinaison de produits provenant à la fois de l'App Store et de Google Play. Ces produits multiplateformes sont intégrés aux paywalls, ce qui vous permet de les afficher dans des placements spécifiques de votre application mobile.
Pour afficher les produits, vous devez obtenir un [Paywall](paywalls) depuis l'un de vos [placements](placements) avec la méthode `getPaywall`.
:::important
**Ne codez pas les ID de produits en dur.** Le seul ID que vous devez coder en dur est l'ID de placement. Les paywalls sont configurés à distance, donc le nombre de produits et les offres disponibles peuvent changer à tout moment. Votre application doit gérer ces changements dynamiquement — si un paywall retourne deux produits aujourd'hui et trois demain, affichez-les tous sans modifier le code.
:::
```kotlin showLineNumbers
Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// the requested paywall
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// the requested paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](android-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option, car elle garantit que vos utilisateurs reçoivent toujours les données les plus récentes.
Toutefois, si vos utilisateurs ont une connexion instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache lorsqu'elles existent. Dans ce cas, les utilisateurs n'auront pas forcément les toutes dernières données, mais les temps de chargement seront plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, ce qui permet de l'utiliser en toute sécurité pendant la session pour éviter les requêtes réseau.
Notez que le cache est conservé après un redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les paywalls sur deux couches : le cache mis à jour régulièrement décrit ci-dessus et les [paywalls de secours](android-use-fallback-paywalls). Nous utilisons également un CDN pour récupérer les paywalls plus rapidement, ainsi qu'un serveur de secours indépendant en cas d'indisponibilité du CDN. Ce système garantit que vous obtenez toujours la dernière version de vos paywalls, tout en assurant la fiabilité même lorsque la connexion est limitée.
|
| **loadTimeout** | par défaut : 5 sec | Cette valeur limite le délai d'expiration de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.
Notez que dans de rares cas, cette méthode peut expirer légèrement après le délai spécifié dans `loadTimeout`, car l'opération peut comprendre plusieurs requêtes en arrière-plan.
|
N'encodez pas les identifiants de produits en dur ! Puisque les paywalls sont configurés à distance, les produits disponibles, leur nombre et les offres spéciales (comme les essais gratuits) peuvent évoluer au fil du temps. Assurez-vous que votre code gère ces scénarios.
Par exemple, si vous récupérez initialement 2 produits, votre application doit afficher ces 2 produits. Mais si vous en récupérez ensuite 3, votre application doit tous les afficher sans nécessiter de modification du code. La seule chose à encoder en dur est l'identifiant du placement.
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Paywall | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) contenant : une liste d'identifiants de produits, l'identifiant du paywall, le Remote Config et plusieurs autres propriétés. |
## Récupérer les produits \{#fetch-products\}
Une fois que vous avez le paywall, vous pouvez récupérer le tableau de produits qui lui correspond :
```kotlin showLineNumbers
Adapty.getPaywallProducts(paywall) { result ->
when (result) {
is AdaptyResult.Success -> {
val products = result.value
// the requested products
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywallProducts(paywall, result -> {
if (result instanceof AdaptyResult.Success) {
List products = ((AdaptyResult.Success>) result).getValue();
// the requested products
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres de réponse :
| Paramètre | Description |
| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Products | Liste d'objets [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) contenant : l'identifiant du produit, le nom du produit, le prix, la devise, la durée de l'abonnement, et plusieurs autres propriétés. |
Lors de l'implémentation de votre propre design de paywall, vous aurez probablement besoin d'accéder à ces propriétés de l'objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/). Les propriétés les plus couramment utilisées sont illustrées ci-dessous, mais consultez le document lié pour obtenir tous les détails sur l'ensemble des propriétés disponibles.
| Propriété | Description |
|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Title** | Pour afficher le titre du produit, utilisez `product.localizedTitle`. La localisation est basée sur le pays du store sélectionné par l'utilisateur, et non sur la langue du terminal. |
| **Price** | Pour afficher une version localisée du prix, utilisez `product.price.localizedString`. La localisation est basée sur les paramètres régionaux du terminal. Vous pouvez également accéder au prix sous forme de nombre avec `product.price.amount`. La valeur est exprimée dans la devise locale. Pour obtenir le symbole de devise associé, utilisez `product.price.currencySymbol`. |
| **Subscription Period** | Pour afficher la période (semaine, mois, année, etc.), utilisez `product.subscriptionDetails?.localizedSubscriptionPeriod`. La localisation est basée sur les paramètres régionaux du terminal. Pour récupérer la période d'abonnement par programmation, utilisez `product.subscriptionDetails?.subscriptionPeriod`. Vous pouvez ensuite accéder à l'enum `unit` pour obtenir la durée (DAY, WEEK, MONTH, YEAR ou UNKNOWN). La valeur `numberOfUnits` indique le nombre d'unités de période. Par exemple, pour un abonnement trimestriel, `unit` vaut `MONTH` et `numberOfUnits` vaut `3`. |
| **Introductory Offer** | Pour afficher un badge ou un indicateur signalant qu'un abonnement contient une offre de lancement, consultez la propriété `product.subscriptionDetails?.introductoryOfferPhases`. Il s'agit d'une liste pouvant contenir jusqu'à deux phases de remise : la phase d'essai gratuit et la phase de prix de lancement. Chaque objet de phase expose les propriétés utiles suivantes :
• `paymentMode` : un enum avec les valeurs `FREE_TRIAL`, `PAY_AS_YOU_GO`, `PAY_UPFRONT` et `UNKNOWN`. Les essais gratuits correspondent au type `FREE_TRIAL`.
• `price` : le prix remisé sous forme de nombre. Pour les essais gratuits, cette valeur est `0`.
• `localizedNumberOfPeriods` : une chaîne localisée selon les paramètres régionaux du terminal, décrivant la durée de l'offre. Par exemple, un essai de trois jours affiche `3 days` dans ce champ.
• `subscriptionPeriod` : vous pouvez également obtenir les détails individuels de la période de l'offre avec cette propriété, qui fonctionne de la même manière que décrit dans la section précédente.
• `localizedSubscriptionPeriod` : une période d'abonnement formatée pour la remise, selon les paramètres régionaux de l'utilisateur. |
## Accélérer la récupération des paywalls avec le paywall d'audience par défaut \{#speed-up-paywall-fetching-with-default-audience-paywall\}
En général, les paywalls sont récupérés presque instantanément, vous n'avez donc pas à vous en préoccuper. Cependant, si vous avez de nombreuses audiences et paywalls et que vos utilisateurs disposent d'une connexion internet faible, la récupération d'un paywall peut prendre plus de temps que souhaité. Dans ces situations, vous pouvez afficher un paywall par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher du tout.
Pour remédier à cela, vous pouvez utiliser la méthode `getPaywallForDefaultAudience`, qui récupère le paywall du placement spécifié pour l'audience **All Users**. Cependant, il est essentiel de comprendre que l'approche recommandée est de récupérer le paywall via la méthode `getPaywall`, comme décrit dans la section [Récupérer les informations du paywall](fetch-paywalls-and-products-android#fetch-paywall-information) ci-dessus.
:::warning
Pourquoi nous recommandons d'utiliser `getPaywall`
La méthode `getPaywallForDefaultAudience` présente quelques inconvénients majeurs :
- **Problèmes potentiels de compatibilité ascendante** : si vous devez afficher des paywalls différents selon les versions de l'application (actuelle et future), vous pourrez rencontrer des difficultés. Vous devrez soit concevoir des paywalls compatibles avec la version actuelle (legacy), soit accepter que les utilisateurs de cette version puissent avoir des problèmes avec des paywalls non rendus.
- **Perte de ciblage** : tous les utilisateurs verront le même paywall conçu pour l'audience **All Users**, ce qui signifie que vous perdez le ciblage personnalisé (y compris par pays, attribution marketing ou vos propres attributs personnalisés).
Si vous acceptez ces inconvénients pour bénéficier d'une récupération plus rapide des paywalls, utilisez la méthode `getPaywallForDefaultAudience` comme suit. Sinon, restez sur `getPaywall` décrit [ci-dessus](fetch-paywalls-and-products-android#fetch-paywall-information).
:::
```kotlin showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// the requested paywall
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
// the requested paywall
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
:::note
La méthode `getPaywallForDefaultAudience` est disponible à partir de la version 2.11.3 du SDK Android.
:::
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **placementId** | requis | L'identifiant du [Placement](placements). C'est la valeur que vous avez spécifiée lors de la création d'un placement dans votre Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la [localisation du paywall](add-remote-config-locale). Ce paramètre doit être un code de langue composé d'un ou plusieurs sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` désigne l'anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](android-localizations-and-locale-codes) pour plus d'informations sur les codes de langue et la façon dont nous recommandons de les utiliser.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et retourne les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Cependant, si vous pensez que vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour retourner les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais ils bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc sans risque de l'utiliser pendant la session pour éviter les requêtes réseau.
Notez que le cache reste intact après le redémarrage de l'application et n'est effacé que lors de la réinstallation de l'application ou via un nettoyage manuel.
|
---
# File: present-remote-config-paywalls-android
---
---
title: "Afficher un paywall conçu par Remote Config dans le SDK Android"
description: "Découvrez comment présenter des paywalls Remote Config dans le SDK Android Adapty pour personnaliser l'expérience utilisateur."
---
Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et l'apparence de votre paywall. Adapty fournit une méthode pour récupérer la configuration distante, vous donnant toute latitude pour présenter votre paywall personnalisé.
## Récupérer la Remote Config d'un flow et l'afficher \{#get-flow-remote-config-and-present-it\}
Dans la v4, un flow contient une entrée `AdaptyRemoteConfig` par locale configurée dans le tableau `remoteConfigs`. Sélectionnez la locale qui correspond à la préférence de l'utilisateur, puis lisez les valeurs dont vous avez besoin.
```kotlin showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val flow = result.value
val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
?: flow.remoteConfigs.firstOrNull()
val headerText = config?.dataMap?.get("header_text") as? String
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getFlow("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyFlow flow = ((AdaptyResult.Success) result).getValue();
AdaptyRemoteConfig config = null;
for (AdaptyRemoteConfig remoteConfig : flow.getRemoteConfigs()) {
if ("en".equals(remoteConfig.getLocale())) {
config = remoteConfig;
break;
}
}
if (config == null && !flow.getRemoteConfigs().isEmpty()) {
config = flow.getRemoteConfigs().get(0);
}
if (config != null && config.getDataMap().get("header_text") instanceof String) {
String headerText = (String) config.getDataMap().get("header_text");
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler en une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des mobiles, pour une expérience fluide et agréable sur tous les appareils.
:::warning
Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-android#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B.
:::
Une fois l'affichage du paywall terminé, configurez le flow d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre flow. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](android-making-purchases).
Nous vous recommandons de [créer un paywall de secours](android-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations.
## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\}
Adapty vous aide à mesurer les performances de vos flows et paywalls. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages nécessite votre intervention, car vous seul savez quand un utilisateur voit un flow.
Pour enregistrer un événement d'affichage, appelez simplement `.logShowFlow(flow)` — cela sera reflété dans vos métriques de funnels et de tests A/B.
:::important
Il n'est pas nécessaire d'appeler `.logShowFlow(flow)` si vous affichez des flows ou des paywalls rendus par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder). Adapty suit les affichages automatiquement dans ces cas.
:::
```kotlin showLineNumbers
Adapty.logShowFlow(flow)
```
Paramètres de la requête :
| Paramètre | Obligatoire | Description |
| :-------- | :------- |:-----------------------------------------------------------------------------------------|
| **flow** | obligatoire | Un objet `AdaptyFlow` obtenu via `Adapty.getFlow`. |
Si vous avez personnalisé un paywall avec Remote Config, vous devrez implémenter le rendu dans le code de votre application mobile pour l'afficher aux utilisateurs. Comme Remote Config offre une flexibilité adaptée à vos besoins, vous contrôlez ce qui est inclus et l'apparence de votre paywall. Nous fournissons une méthode pour récupérer la configuration distante, vous donnant toute latitude pour présenter votre paywall personnalisé configuré via Remote Config.
## Récupérer la Remote Config d'un paywall et l'afficher \{#get-paywall-remote-config-and-present-it\}
Pour obtenir la Remote Config d'un paywall, accédez à la propriété `remoteConfig` et extrayez les valeurs nécessaires.
```kotlin showLineNumbers
Adapty.getPaywall("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getPaywall("YOUR_PLACEMENT_ID", result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue();
AdaptyPaywall.RemoteConfig remoteConfig = paywall.getRemoteConfig();
if (remoteConfig != null) {
if (remoteConfig.getDataMap().get("header_text") instanceof String) {
String headerText = (String) remoteConfig.getDataMap().get("header_text");
}
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
À ce stade, une fois toutes les valeurs nécessaires récupérées, il est temps de les assembler en une page visuellement attrayante. Veillez à ce que le design s'adapte aux différentes tailles d'écran et orientations des mobiles, pour une expérience fluide et agréable sur tous les appareils.
:::warning
Veillez à [enregistrer l'événement d'affichage du paywall](present-remote-config-paywalls-android#track-paywall-view-events) comme décrit ci-dessous, afin qu'Adapty Analytics puisse collecter les données pour les funnels et les tests A/B.
:::
Une fois l'affichage du paywall terminé, configurez le flow d'achat. Lorsque l'utilisateur effectue un achat, appelez simplement `.makePurchase()` avec le produit de votre paywall. Pour plus de détails sur la méthode `.makePurchase()`, consultez [Effectuer des achats](android-making-purchases).
Nous vous recommandons de [créer un paywall de secours](android-use-fallback-paywalls). Ce paywall de secours s'affichera pour l'utilisateur en l'absence de connexion internet ou de cache disponible, garantissant une expérience fluide même dans ces situations.
## Suivre les événements d'affichage du paywall \{#track-paywall-view-events\}
Adapty vous aide à mesurer les performances de vos paywalls. Bien que nous collectons automatiquement les données sur les achats, l'enregistrement des affichages nécessite votre intervention, car vous seul savez quand un utilisateur voit un paywall.
Pour enregistrer un événement d'affichage de paywall, appelez simplement `.logShowPaywall(paywall)` — cela sera reflété dans vos métriques de paywall dans les funnels et les tests A/B.
:::important
Il n'est pas nécessaire d'appeler `.logShowPaywall(paywall)` si vous affichez des paywalls créés dans le [Paywall Builder](adapty-paywall-builder).
:::
```kotlin showLineNumbers
Adapty.logShowPaywall(paywall)
```
Paramètres de la requête :
| Paramètre | Obligatoire | Description |
| :---------- | :------- |:------------------------------------------------------------------------------------------------------------|
| **paywall** | obligatoire | Un objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
---
# File: android-making-purchases
---
---
title: "Effectuer des achats dans une application mobile avec le SDK Android"
description: "Guide sur la gestion des achats intégrés et des abonnements avec Adapty."
---
Afficher des paywalls dans votre application mobile est une étape essentielle pour offrir aux utilisateurs l'accès à des contenus ou services premium. Cependant, se contenter d'afficher ces paywalls suffit à gérer les achats uniquement si vous utilisez le [Paywall Builder](adapty-paywall-builder) pour les personnaliser.
Si vous n'utilisez pas le Paywall Builder, vous devez utiliser une méthode dédiée appelée `.makePurchase()` pour finaliser un achat et débloquer le contenu souhaité. Cette méthode sert de point d'entrée pour que les utilisateurs interagissent avec les paywalls et procèdent à leurs transactions.
Si votre paywall comporte une offre promotionnelle active pour le produit qu'un utilisateur souhaite acheter, Adapty l'appliquera automatiquement au moment de l'achat.
:::warning
Gardez à l'esprit que l'offre de lancement ne sera appliquée automatiquement que si vous utilisez des paywalls configurés avec le Paywall Builder.
Dans les autres cas, vous devrez [vérifier l'éligibilité de l'utilisateur à une offre de lancement sur iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Ignorer cette étape peut entraîner le rejet de votre application lors de la publication. De plus, cela pourrait conduire à facturer le plein tarif à des utilisateurs pourtant éligibles à une offre de lancement.
:::
Assurez-vous d'avoir [effectué la configuration initiale](quickstart) sans sauter la moindre étape. Sans elle, nous ne pouvons pas valider les achats.
## Effectuer un achat \{#make-purchase\}
:::note
**Vous utilisez le [Paywall Builder](adapty-paywall-builder) ?** Les achats sont traités automatiquement — vous pouvez ignorer cette étape.
**Vous cherchez un guide pas à pas ?** Consultez le [guide de démarrage rapide](android-implement-paywalls-manually) pour des instructions d'implémentation complètes avec tout le contexte nécessaire.
:::
```kotlin showLineNumbers
Adapty.makePurchase(activity, product, null) { result ->
when (result) {
is AdaptyResult.Success -> {
when (val purchaseResult = result.value) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
// Grant access to the paid features
}
}
is AdaptyPurchaseResult.UserCanceled -> {
// Handle the case where the user canceled the purchase
}
is AdaptyPurchaseResult.Pending -> {
// Handle deferred purchases (e.g., the user will pay offline with cash)
}
}
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
```
```java showLineNumbers
Adapty.makePurchase(activity, product, null, result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue();
if (purchaseResult instanceof AdaptyPurchaseResult.Success) {
AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile();
AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL");
if (premium != null && premium.isActive()) {
// Grant access to the paid features
}
} else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) {
// Handle the case where the user canceled the purchase
} else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) {
// Handle deferred purchases (e.g., the user will pay offline with cash)
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle the error
}
});
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| :---------- | :------- | :-------------------------------------------------------------------------------------------------- |
| **Product** | requis | Un objet [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) récupéré depuis le paywall. |
Paramètres de la réponse :
| Paramètre | Description |
|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Profile** | Si la requête a réussi, la réponse contient cet objet. Un objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/) fournit des informations complètes sur les niveaux d'accès, les abonnements et les achats uniques d'un utilisateur dans l'application.
Vérifiez le statut du niveau d'accès pour déterminer si l'utilisateur dispose de l'accès requis à l'application.
|
:::warning
**Remarque :** si vous utilisez encore une version de StoreKit d'Apple inférieure à v2.0 et une version du SDK Adapty inférieure à v2.9.0, vous devez fournir le [secret partagé de l'App Store Apple](app-store-connection-configuration#step-5-enter-app-store-shared-secret) à la place. Cette méthode est actuellement dépréciée par Apple.
:::
## Changer d'abonnement lors d'un achat \{#change-subscription-when-making-a-purchase\}
Lorsqu'un utilisateur choisit un nouvel abonnement plutôt que de renouveler l'abonnement en cours, le fonctionnement dépend du store. Sur Google Play, l'abonnement n'est pas mis à jour automatiquement. Vous devrez gérer le changement dans le code de votre application mobile comme décrit ci-dessous.
Pour remplacer un abonnement par un autre sur Android, appelez la méthode `.makePurchase()` avec le paramètre supplémentaire suivant :
```kotlin showLineNumbers
Adapty.makePurchase(
activity,
product,
AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(subscriptionUpdateParams)
.build()
) { result ->
when (result) {
is AdaptyResult.Success -> {
when (val purchaseResult = result.value) {
is AdaptyPurchaseResult.Success -> {
val profile = purchaseResult.profile
// successful cross-grade
}
is AdaptyPurchaseResult.UserCanceled -> {
// user canceled the purchase flow
}
is AdaptyPurchaseResult.Pending -> {
// the purchase has not been finished yet, e.g. user will pay offline by cash
}
}
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
```
Paramètre de requête supplémentaire :
| Paramètre | Présence | Description |
| :--------------------------- | :------- | :----------------------------------------------------------- |
| **subscriptionUpdateParams** | requis | un objet [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/). |
```java showLineNumbers
Adapty.makePurchase(
activity,
product,
new AdaptyPurchaseParameters.Builder()
.withSubscriptionUpdateParams(subscriptionUpdateParams)
.build(),
result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue();
if (purchaseResult instanceof AdaptyPurchaseResult.Success) {
AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile();
// successful cross-grade
} else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) {
// user canceled the purchase flow
} else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) {
// the purchase has not been finished yet, e.g. user will pay offline by cash
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// Handle the error
}
});
```
Paramètre de requête supplémentaire :
| Paramètre | Présence | Description |
| :--------------------------- | :------- | :----------------------------------------------------------- |
| **subscriptionUpdateParams** | requis | un objet [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/). |
Pour en savoir plus sur les abonnements et les modes de remplacement, consultez la documentation Google Developer :
- [À propos des modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-modes)
- [Recommandations de Google pour les modes de remplacement](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations)
- Mode de remplacement [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Remarque : cette méthode est disponible uniquement pour les mises à niveau d'abonnement. Les rétrogradations ne sont pas prises en charge.
- Mode de remplacement [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Remarque : le changement d'abonnement effectif n'aura lieu qu'à la fin de la période de facturation en cours.
### Gérer les plans prépayés \{#manage-prepaid-plans\}
Si les utilisateurs de votre application peuvent acheter des [plans prépayés](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans) (par exemple, souscrire à un abonnement non renouvelable pour plusieurs mois), vous pouvez activer les [transactions en attente](https://developer.android.com/google/play/billing/subscriptions#pending) pour ces plans.
```kotlin showLineNumbers
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withEnablePendingPrepaidPlans(true)
.build()
```
```java showLineNumbers
new AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withEnablePendingPrepaidPlans(true)
.build();
```
---
# File: android-restore-purchase
---
---
title: "Restaurer les achats dans une application mobile avec le SDK Android"
description: "Apprenez comment restaurer les achats dans Adapty pour garantir une expérience utilisateur fluide."
---
La restauration des achats est une fonctionnalité qui permet aux utilisateurs de récupérer l'accès à des contenus précédemment achetés — abonnements ou achats intégrés — sans être facturés à nouveau. Elle est particulièrement utile pour les utilisateurs qui ont désinstallé puis réinstallé l'application, ou qui ont changé d'appareil et souhaitent retrouver leurs achats sans repayer.
:::note
Dans les paywalls créés avec le [Paywall Builder](adapty-paywall-builder), les achats sont restaurés automatiquement, sans code supplémentaire de votre part. Si c'est votre cas, vous pouvez ignorer cette étape.
:::
Pour restaurer un achat sans utiliser le [Paywall Builder](adapty-paywall-builder), appelez la méthode `.restorePurchases()` :
```kotlin showLineNumbers
Adapty.restorePurchases { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
// successful access restore
}
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.restorePurchases(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
if (profile != null) {
AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL");
if (premium != null && premium.isActive()) {
// successful access restore
}
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres de la réponse :
| Paramètre | Description |
|---------|-----------|
| **Profile** | Un objet [`AdaptyProfile`](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Ce modèle contient des informations sur les niveaux d'accès, les abonnements et les achats uniques.
Vérifiez le **statut du niveau d'accès** pour déterminer si l'utilisateur a accès à l'application.
|
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
---
# File: implement-observer-mode-android
---
---
title: "Implémenter le mode Observer dans le SDK Android"
description: "Implémentez le mode Observer dans Adapty pour suivre les événements d'abonnement des utilisateurs dans le SDK Android."
---
Si vous avez déjà votre propre infrastructure d'achats et n'êtes pas encore prêt à passer entièrement à Adapty, vous pouvez explorer le [mode Observer](observer-vs-full-mode). Dans sa forme de base, le mode Observer offre des analyses avancées et une intégration transparente avec les systèmes d'attribution et d'analyse.
Si cela répond à vos besoins, vous devez uniquement :
1. L'activer lors de la configuration du SDK Adapty en définissant le paramètre `observerMode` sur `true`. Suivez les instructions de configuration pour [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk).
2. [Signaler les transactions](report-transactions-observer-mode-android) depuis votre infrastructure d'achats existante à Adapty.
## Configuration du mode Observer \{#observer-mode-setup\}
Activez le mode Observer si vous gérez vous-même les achats et l'état des abonnements, et que vous utilisez Adapty pour envoyer des événements d'abonnement et des analyses.
:::important
En mode Observer, le SDK Adapty ne clôture aucune transaction — assurez-vous donc de les gérer vous-même.
:::
```kotlin showLineNumbers
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Adapty.activate(
applicationContext,
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withObserverMode(true) //default false
.build()
)
}
```
```java showLineNumbers
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Adapty.activate(
applicationContext,
new AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withObserverMode(true) //default false
.build()
);
}
```
Paramètres :
| Paramètre | Description |
| --------------------------- | ------------------------------------------------------------ |
| observerMode | Valeur booléenne qui contrôle le [mode Observer](observer-vs-full-mode). La valeur par défaut est `false`. |
## Utiliser les paywalls Adapty en mode Observer \{#using-adapty-paywalls-in-observer-mode\}
Si vous souhaitez également utiliser les paywalls et les fonctionnalités de test A/B d'Adapty, c'est possible — mais cela nécessite une configuration supplémentaire en mode Observer. Voici ce que vous devrez faire en plus des étapes ci-dessus :
1. Affichez les paywalls normalement pour les [paywalls Remote Config](present-remote-config-paywalls-android). Pour les paywalls Paywall Builder, suivez les guides de configuration spécifiques pour [Android](android-present-paywall-builder-paywalls-in-observer-mode).
3. [Associez les paywalls](report-transactions-observer-mode-android) aux transactions d'achat.
---
# File: report-transactions-observer-mode-android
---
---
title: "Signaler les transactions en Observer Mode dans le SDK Android"
description: "Signalez les transactions d'achat en Adapty Observer Mode pour les informations utilisateurs et le suivi des revenus dans le SDK Android."
---
En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses.
Utilisez `reportTransaction` pour signaler explicitement chaque transaction afin qu'Adapty la reconnaisse.
:::warning
**Ne sautez pas le signalement des transactions !**
Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations.
:::
Si vous utilisez des paywalls Adapty, incluez le `variationId` lors du signalement d'une transaction. Cela relie l'achat au paywall qui l'a déclenché, garantissant ainsi des analyses de paywall précises.
```kotlin showLineNumbers
val transactionInfo = TransactionInfo.fromPurchase(purchase)
Adapty.reportTransaction(transactionInfo, variationId) { result ->
if (result is AdaptyResult.Success) {
// success
}
}
```
Paramètres :
| Paramètre | Présence | Description |
| --------------- | --------- | ------------------------------------------------------------ |
| transactionInfo | obligatoire | Le TransactionInfo issu de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | optionnel | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
```java showLineNumbers
TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase);
Adapty.reportTransaction(transactionInfo, variationId, result -> {
if (result instanceof AdaptyResult.Success) {
// success
}
});
```
Paramètres :
| Paramètre | Présence | Description |
| --------------- | --------- | ------------------------------------------------------------ |
| transactionInfo | obligatoire | Le TransactionInfo issu de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | optionnel | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
En Observer Mode, le SDK Adapty ne peut pas suivre automatiquement les achats effectués via votre système d'achat existant. Vous devez signaler les transactions depuis votre app store ou les restaurer. Il est indispensable de configurer cela **avant** de publier votre application pour éviter des erreurs dans les analyses.
Utilisez `restorePurchases` pour signaler la transaction à Adapty.
:::warning
**Ne sautez pas la restauration des achats !**
Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations.
:::
Si vous utilisez des paywalls Adapty, associez votre transaction au paywall qui a conduit à l'achat via la méthode `setVariationId`. Cela garantit que l'achat est correctement attribué au paywall déclencheur pour des analyses précises. Cette étape n'est nécessaire que si vous utilisez des paywalls Adapty.
```kotlin showLineNumbers
Adapty.restorePurchases { result ->
if (result is AdaptyResult.Success) {
// success
}
}
Adapty.setVariationId(transactionId, variationId) { error ->
if (error == null) {
// success
}
}
```
Paramètres :
| Paramètre | Présence | Description |
| ------------- | --------- | ------------------------------------------------------------ |
| transactionId | obligatoire | Identifiant string (`purchase.getOrderId`) de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
```java showLineNumbers
Adapty.restorePurchases(result -> {
if (result instanceof AdaptyResult.Success) {
// success
}
});
Adapty.setVariationId(transactionId, variationId, error -> {
if (error == null) {
// success
}
});
```
Paramètres :
| Paramètre | Présence | Description |
| ------------- | --------- | ------------------------------------------------------------ |
| transactionId | obligatoire | Identifiant string (`purchase.getOrderId`) de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
**Signalement des transactions**
Utilisez `restorePurchases` pour signaler une transaction à Adapty en Observer Mode, comme expliqué sur la page [Restaurer les achats dans le code mobile](android-restore-purchase).
:::warning
**Ne sautez pas le signalement des transactions !**
Si vous n'appelez pas `restorePurchases`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations.
:::
**Association des paywalls aux transactions**
Le SDK Adapty ne peut pas déterminer la source des achats, car c'est vous qui les traitez. Par conséquent, si vous comptez utiliser des paywalls et/ou des tests A/B en Observer Mode, vous devez associer la transaction provenant de votre app store au paywall correspondant dans le code de votre application mobile. Il est important de faire cela correctement avant de publier votre application, sinon cela entraînera des erreurs dans les analyses.
```kotlin
Adapty.setVariationId(transactionId, variationId) { error ->
if (error == null) {
// success
}
}
```
Paramètres de la requête :
| Paramètre | Présence | Description |
| ------------- | --------- | ------------------------------------------------------------ |
| transactionId | obligatoire | Identifiant string (purchase.getOrderId de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
```java
Adapty.setVariationId(transactionId, variationId, error -> {
if (error == null) {
// success
}
});
```
| Paramètre | Présence | Description |
| ------------------------------------------------- | --------- | ------------------------------------------------------------ |
| transactionId | obligatoire | Identifiant string (purchase.getOrderId de l'achat, où purchase est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation. |
| variationId | obligatoire | L'identifiant string de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
---
# File: android-present-paywall-builder-paywalls-in-observer-mode
---
---
title: "Présenter les paywalls du Paywall Builder en mode Observer dans le SDK Android"
description: "Découvrez comment présenter les paywalls en mode observer avec le Paywall Builder d'Adapty."
---
Si vous avez créé un flow ou un paywall avec le Flow Builder ou le Paywall Builder, vous n'avez pas besoin de vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et comment l'afficher.
:::warning
Cette section concerne uniquement le [mode Observer](observer-vs-full-mode). Si vous ne travaillez pas en mode Observer, consultez plutôt la rubrique [Android - Afficher les flows et paywalls](android-present-paywalls).
:::
Avant de commencer à afficher des flows (cliquez pour développer)
1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android).
2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à votre framework [pour Android](sdk-installation-android).
3. [Créez des produits](create-product) dans l'Adapty Dashboard.
4. [Configurez des flows ou des paywalls dans les builders](create-paywall) et assignez-leur des produits.
5. [Créez des placements et assignez-leur vos flows ou paywalls](create-placement) dans l'Adapty Dashboard.
6. [Récupérez les flows et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.
1. Implémentez l'`AdaptyUiObserverModeHandler`.
L'événement `onPurchaseInitiated` vous informe que l'utilisateur a lancé un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback :
```kotlin showLineNumbers
val observerModeHandler =
AdaptyUiObserverModeHandler { product, flow, flowView, onStartPurchase, onFinishPurchase ->
onStartPurchase()
yourBillingClient.makePurchase(
product,
onSuccess = { purchase ->
onFinishPurchase()
//handle success
},
onError = {
onFinishPurchase()
//handle error
},
onCancel = {
onFinishPurchase()
//handle cancel
}
)
}
```
```java showLineNumbers
AdaptyUiObserverModeHandler observerModeHandler = (product, flow, flowView, onStartPurchase, onFinishPurchase) -> {
onStartPurchase.invoke();
yourBillingClient.makePurchase(
product,
purchase -> {
onFinishPurchase.invoke();
//handle success
},
error -> {
onFinishPurchase.invoke();
//handle error
},
() -> { //cancellation
onFinishPurchase.invoke();
//handle cancel
}
);
};
```
Pour gérer les restaurations en mode Observer, surchargez `getRestoreHandler()`. Par défaut, il retourne `null`, ce qui utilise le flow intégré `Adapty.restorePurchases()` d'Adapty. Pour fournir votre propre implémentation de restauration :
```kotlin showLineNumbers
val observerModeHandler = object : AdaptyUiObserverModeHandler {
// onPurchaseInitiated implementation (see above)
override fun getRestoreHandler() =
AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore ->
onStartRestore()
yourBillingClient.restorePurchases(
onSuccess = { restoredPurchases ->
onFinishRestore()
//handle successful restore
},
onError = {
onFinishRestore()
//handle error
}
)
}
}
```
```java showLineNumbers
AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() {
// onPurchaseInitiated implementation (see above)
@Override
public RestoreHandler getRestoreHandler() {
return (onStartRestore, onFinishRestore) -> {
onStartRestore.invoke();
yourBillingClient.restorePurchases(
restoredPurchases -> {
onFinishRestore.invoke();
//handle successful restore
},
error -> {
onFinishRestore.invoke();
//handle error
}
);
};
}
};
```
N'oubliez pas d'appeler les callbacks suivants pour notifier AdaptyUI de l'avancement du processus d'achat ou de restauration. Cela est nécessaire pour le bon fonctionnement du flow, notamment pour l'affichage du chargement :
| Callback | Description |
| :----------------- |:---------------------------------------------------------------------------------------------------------------|
| onStartPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. |
| onFinishPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. |
| onStartRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration a démarré. |
| onFinishRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration est terminée. |
2. Pour afficher le flow visuel sur l'écran de l'appareil, vous devez d'abord le configurer.
Pour ce faire, appelez la méthode `AdaptyUI.getFlowView()` ou créez directement le `AdaptyFlowView` :
```kotlin showLineNumbers
val flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
observerModeHandler,
)
```
```kotlin showLineNumbers
val flowView =
AdaptyFlowView(activity) // or retrieve it from xml
...
with(flowView) {
showFlow(
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
observerModeHandler,
)
}
```
```java showLineNumbers
AdaptyFlowView flowView = AdaptyUI.getFlowView(
activity,
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
observerModeHandler
);
```
```java showLineNumbers
AdaptyFlowView flowView =
new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler);
```
```xml showLineNumbers
```
Après la création réussie de la vue, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher.
Pour ce faire, utilisez cette fonction composable :
```kotlin showLineNumbers
AdaptyFlowScreen(
flowConfiguration,
products,
eventListener,
insets,
customAssets,
tagResolver,
timerResolver,
observerModeHandler,
)
```
Paramètres de la requête :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **flowConfiguration** | obligatoire | Fournissez un objet `AdaptyUI.FlowConfiguration` contenant les détails visuels du flow. Utilisez la méthode `AdaptyUI.getFlowConfiguration(flow)` pour le charger. Consultez la rubrique [Récupérer la configuration de la vue](android-get-pb-paywalls#fetch-the-view-configuration) pour plus de détails. |
| **products** | optionnel | Fournissez un tableau de `AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupèrera automatiquement les produits requis. |
| **eventListener** | optionnel | Fournissez un `AdaptyFlowEventListener` pour observer les événements du flow. L'extension de `AdaptyFlowDefaultEventListener` est recommandée pour faciliter l'utilisation. Consultez la rubrique [Gérer les événements de flow et de paywall](android-handling-events) pour plus de détails. |
| **insets** | optionnel | Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués derrière les barres système. Par défaut : `Unspecified`, ce qui laisse Adapty ajuster les insets automatiquement. Voir [Modifier les insets du flow](android-present-paywalls#change-flow-insets). |
| **customAssets** | optionnel | Passez un objet `AdaptyCustomAssets` pour remplacer les images et vidéos de votre flow ou paywall au moment de l'exécution. Consultez [Personnaliser les assets](android-get-pb-paywalls#customize-assets) pour plus de détails. |
| **tagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du flow. Ce resolver prend un paramètre de balise et le résout en chaîne de caractères correspondante. Consultez la rubrique Balises personnalisées dans le Paywall Builder pour plus de détails. |
| **observerModeHandler** | obligatoire pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. |
:::warning
N'oubliez pas d'[associer les paywalls aux transactions d'achat](report-transactions-observer-mode-android). Sinon, Adapty ne pourra pas déterminer le flow source de l'achat.
:::
Avant de commencer à présenter des paywalls (Cliquez pour développer)
1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios).
2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à chaque framework [pour Android](sdk-installation-android).
3. [Créez des produits](create-product) dans l'Adapty Dashboard.
4. [Configurez des paywalls, assignez-leur des produits](create-paywall) et personnalisez-les à l'aide du Paywall Builder dans l'Adapty Dashboard.
5. [Créez des placements et assignez-y vos paywalls](create-placement) dans l'Adapty Dashboard.
6. [Récupérez les paywalls Paywall Builder et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.
1. Implémentez `AdaptyUiObserverModeHandler`.
L'événement `onPurchaseInitiated` vous informe que l'utilisateur a initié un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback :
```kotlin showLineNumbers
val observerModeHandler =
AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase ->
onStartPurchase()
yourBillingClient.makePurchase(
product,
onSuccess = { purchase ->
onFinishPurchase()
//handle success
},
onError = {
onFinishPurchase()
//handle error
},
onCancel = {
onFinishPurchase()
//handle cancel
}
)
}
```
```java showLineNumbers
AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> {
onStartPurchase.invoke();
yourBillingClient.makePurchase(
product,
purchase -> {
onFinishPurchase.invoke();
//handle success
},
error -> {
onFinishPurchase.invoke();
//handle error
},
() -> { //cancellation
onFinishPurchase.invoke();
//handle cancel
}
);
};
```
Pour gérer les restaurations en mode Observer, surchargez `getRestoreHandler()`. Par défaut, elle retourne `null`, ce qui utilise le flow intégré d'Adapty `Adapty.restorePurchases()`. Pour fournir votre propre implémentation de restauration :
```kotlin showLineNumbers
val observerModeHandler = object : AdaptyUiObserverModeHandler {
// onPurchaseInitiated implementation (see above)
override fun getRestoreHandler() =
AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore ->
onStartRestore()
yourBillingClient.restorePurchases(
onSuccess = { restoredPurchases ->
onFinishRestore()
//handle successful restore
},
onError = {
onFinishRestore()
//handle error
}
)
}
}
```
```java showLineNumbers
AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() {
// onPurchaseInitiated implementation (see above)
@Override
public RestoreHandler getRestoreHandler() {
return (onStartRestore, onFinishRestore) -> {
onStartRestore.invoke();
yourBillingClient.restorePurchases(
restoredPurchases -> {
onFinishRestore.invoke();
//handle successful restore
},
error -> {
onFinishRestore.invoke();
//handle error
}
);
};
}
};
```
N'oubliez pas d'invoquer les callbacks suivants pour notifier AdaptyUI du processus d'achat ou de restauration. Ceci est nécessaire pour un comportement correct du paywall, comme l'affichage du chargeur :
| Callback | Description |
| :----------------- |:---------------------------------------------------------------------------------------------------|
| onStartPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. |
| onFinishPurchase() | Le callback doit être invoqué pour notifier AdaptyUI que l'achat est terminé. |
| onStartRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration a démarré. |
| onFinishRestore() | Optionnel. Le callback peut être invoqué pour notifier AdaptyUI que la restauration est terminée. |
2. Pour afficher le paywall visuel à l'écran de l'appareil, vous devez d'abord le configurer.
Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement `AdaptyPaywallView` :
```kotlin showLineNumbers
val paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
eventListener,
personalizedOfferResolver,
tagResolver,
timerResolver,
observerModeHandler,
)
```
```kotlin showLineNumbers
val paywallView =
AdaptyPaywallView(activity) // or retrieve it from xml
...
with(paywallView) {
showPaywall(
viewConfiguration,
products,
eventListener,
personalizedOfferResolver,
tagResolver,
timerResolver,
observerModeHandler,
)
}
```
```java showLineNumbers
AdaptyPaywallView paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
eventListener,
personalizedOfferResolver,
tagResolver,
timerResolver,
observerModeHandler
);
```
```java showLineNumbers
AdaptyPaywallView paywallView =
new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
paywallView.showPaywall(viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler);
```
```xml showLineNumbers
```
Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher.
Pour ce faire, utilisez cette fonction composable :
```kotlin showLineNumbers
AdaptyPaywallScreen(
viewConfiguration,
products,
eventListener,
personalizedOfferResolver,
tagResolver,
timerResolver,
)
```
Paramètres de la requête :
| Paramètre | Présence | Description |
|---------|--------|-----------|
| **Products** | optionnel | Fournissez un tableau d'`AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupère automatiquement les produits requis. |
| **ViewConfiguration** | requis | Fournissez un objet `AdaptyViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. |
| **EventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour simplifier l'utilisation. Consultez la rubrique [Gestion des événements du paywall](android-handling-events) pour plus de détails. |
| **PersonalizedOfferResolver** | optionnel | Pour indiquer une tarification personnalisée ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et transmettez votre propre logique qui associe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. |
| **TagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le transforme en chaîne correspondante. Consultez la rubrique Tags personnalisés dans le Paywall Builder pour plus de détails. |
| **ObserverModeHandler** | requis pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. |
| **variationId** | requis | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
| **transaction** | requis | Pour iOS, StoreKit 1 : un objet [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Pour Android : l'identifiant de type String (`purchase.getOrderId()`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.
|
Avant de commencer à afficher les paywalls (Cliquez pour développer)
1. Configurez l'intégration initiale d'Adapty [avec Google Play](initial-android) et [avec l'App Store](initial_ios).
2. Installez et configurez le SDK Adapty. Assurez-vous de définir le paramètre `observerMode` sur `true`. Consultez nos instructions spécifiques à chaque framework [pour Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk) et [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk).
3. [Créez des produits](create-product) dans l'Adapty Dashboard.
4. [Configurez des paywalls, associez-leur des produits](create-paywall) et personnalisez-les à l'aide du Paywall Builder dans l'Adapty Dashboard.
5. [Créez des placements et associez-leur vos paywalls](create-placement) dans l'Adapty Dashboard.
6. [Récupérez les paywalls créés avec le Paywall Builder et leur configuration](android-get-pb-paywalls) dans le code de votre application mobile.
1. Implémentez `AdaptyUiObserverModeHandler`. Le callback de `AdaptyUiObserverModeHandler` (`onPurchaseInitiated`) vous informe lorsqu'un utilisateur initie un achat. Vous pouvez déclencher votre flow d'achat personnalisé en réponse à ce callback de la façon suivante :
```kotlin showLineNumbers
val observerModeHandler =
AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase ->
onStartPurchase()
yourBillingClient.makePurchase(
product,
onSuccess = { purchase ->
onFinishPurchase()
//handle success
},
onError = {
onFinishPurchase()
//handle error
},
onCancel = {
onFinishPurchase()
//handle cancel
}
)
}
```
```java showLineNumbers
AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> {
onStartPurchase.invoke();
yourBillingClient.makePurchase(
product,
purchase -> {
onFinishPurchase.invoke();
//handle success
},
error -> {
onFinishPurchase.invoke();
//handle error
},
() -> { //cancellation
onFinishPurchase.invoke();
//handle cancel
}
);
};
```
Également, n'oubliez pas d'appeler ces callbacks sur AdaptyUI. Cela est nécessaire pour le bon fonctionnement du paywall, comme l'affichage du chargeur, entre autres :
| Callback en Kotlin | Callback en Java | Description |
| :----------------- | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| onStartPurchase() | onStartPurchase.invoke() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat a démarré. |
| onFinishPurchase() | onFinishPurchase.invoke() | Ce callback doit être invoqué pour notifier AdaptyUI que l'achat s'est terminé avec succès, a échoué ou a été annulé. |
2. Pour afficher le paywall visuel, vous devez d'abord l'initialiser. Pour ce faire, appelez la méthode `AdaptyUI.getPaywallView()` ou créez directement l'`AdaptyPaywallView` :
```kotlin showLineNumbers
val paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
AdaptyPaywallInsets.of(topInset, bottomInset),
eventListener,
personalizedOfferResolver,
tagResolver,
observerModeHandler,
)
//======= OR =======
val paywallView =
AdaptyPaywallView(activity) // or retrieve it from xml
...
with(paywallView) {
setEventListener(eventListener)
setObserverModeHandler(observerModeHandler)
showPaywall(
viewConfiguration,
products,
AdaptyPaywallInsets.of(topInset, bottomInset),
personalizedOfferResolver,
tagResolver,
)
}
```
```java showLineNumbers
AdaptyPaywallView paywallView = AdaptyUI.getPaywallView(
activity,
viewConfiguration,
products,
AdaptyPaywallInsets.of(topInset, bottomInset),
eventListener,
personalizedOfferResolver,
tagResolver,
observerModeHandler
);
//======= OR =======
AdaptyPaywallView paywallView =
new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
paywallView.setEventListener(eventListener);
paywallView.setObserverModeHandler(observerModeHandler);
paywallView.showPaywall(viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), personalizedOfferResolver);
```
```xml showLineNumbers
```
Après la création réussie de la vue, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher.
Paramètres de la requête :
| Paramètre | Présence | Description |
|---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Products** | optionnel | Fournissez un tableau d'`AdaptyPaywallProduct` pour optimiser le moment d'affichage des produits à l'écran. Si `null` est passé, AdaptyUI récupèrera automatiquement les produits requis. |
| **ViewConfiguration** | requis | Fournissez un objet `AdaptyViewConfiguration` contenant les détails visuels du paywall. Utilisez la méthode `Adapty.getViewConfiguration(paywall)` pour le charger. Consultez la rubrique [Récupérer la configuration visuelle du paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) pour plus de détails. |
| **Insets** | requis | Définissez un objet `AdaptyPaywallInsets` contenant les informations sur la zone chevauchée par les barres système, créant ainsi des marges verticales pour le contenu. Si ni la barre de statut ni la barre de navigation ne chevauchent l'`AdaptyPaywallView`, passez `AdaptyPaywallInsets.NONE`. En mode plein écran où les barres système chevauchent une partie de votre interface, obtenez les insets comme indiqué sous le tableau. |
| **EventListener** | optionnel | Fournissez un `AdaptyUiEventListener` pour observer les événements du paywall. Il est recommandé d'étendre `AdaptyUiDefaultEventListener` pour plus de simplicité. Consultez la rubrique [Gestion des événements du paywall](android-handling-events) pour plus de détails. |
| **PersonalizedOfferResolver** | optionnel | Pour indiquer une tarification personnalisée ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), implémentez `AdaptyUiPersonalizedOfferResolver` et passez votre propre logique qui associe `AdaptyPaywallProduct` à `true` si le prix du produit est personnalisé, sinon `false`. |
| **TagResolver** | optionnel | Utilisez `AdaptyUiTagResolver` pour résoudre les balises personnalisées dans le texte du paywall. Ce résolveur prend un paramètre de balise et le résout en une chaîne correspondante. Consultez la rubrique Custom tags in Paywall Builder pour plus de détails. |
| **ObserverModeHandler** | requis pour le mode Observer | L'`AdaptyUiObserverModeHandler` que vous avez implémenté à l'étape précédente. |
| **variationId** | requis | L'identifiant de chaîne de la variante. Vous pouvez l'obtenir via la propriété `variationId` de l'objet [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/). |
| **transaction** | requis | Pour iOS, StoreKit 1 : un objet [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Pour iOS, StoreKit 2 : un objet [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Pour Android : l'identifiant de chaîne (`purchase.getOrderId()`) de l'achat, où l'achat est une instance de la classe [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la bibliothèque de facturation.
|
Pour le mode plein écran où les barres système chevauchent une partie de votre interface, obtenez les insets de la manière suivante :
```kotlin showLineNumbers
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
//create extension function
fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
ViewCompat.setOnApplyWindowInsetsListener(this, null)
action(systemBarInsets)
insets
}
}
//and then use it with the view
paywallView.onReceiveSystemBarsInsets { insets ->
val paywallInsets = AdaptyPaywallInsets.of(insets.top, insets.bottom)
paywallView.setEventListener(eventListener)
paywallView.setObserverModeHandler(observerModeHandler)
paywallView.showPaywall(viewConfig, products, paywallInsets, personalizedOfferResolver, tagResolver)
}
```
```java showLineNumbers
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
...
ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> {
Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewCompat.setOnApplyWindowInsetsListener(paywallView, null);
AdaptyPaywallInsets paywallInsets =
AdaptyPaywallInsets.of(systemBarInsets.top, systemBarInsets.bottom);
paywallView.setEventListener(eventListener);
paywallView.setObserverModeHandler(observerModeHandler);
paywallView.showPaywall(viewConfiguration, products, paywallInsets, personalizedOfferResolver, tagResolver);
return insets;
});
```
Returns:
| Objet | Description |
| :------------------ | :------------------------------------------------- |
| `AdaptyPaywallView` | Objet représentant l'écran de paywall demandé. |
:::warning
N'oubliez pas d'[Associer les paywalls aux transactions d'achat](report-transactions-observer-mode-android). Sinon, Adapty ne pourra pas déterminer le paywall source de l'achat.
:::
---
# File: android-troubleshoot-purchases
---
---
title: "Troubleshoot purchases in Android SDK"
description: "Troubleshoot purchases in Android SDK"
---
Ce guide vous aide à résoudre les problèmes courants lors de l'implémentation manuelle des achats dans le SDK Android.
## makePurchase est appelé avec succès, mais le profil n'est pas mis à jour \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\}
**Problème** : La méthode `makePurchase` se termine avec succès, mais le profil de l'utilisateur et son statut d'abonnement ne sont pas mis à jour dans Adapty.
**Raison** : Cela indique généralement une configuration incomplète du Google Play Store.
**Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android).
## makePurchase est appelé deux fois \{#makepurchase-is-invoked-twice\}
**Problème** : La méthode `makePurchase` est appelée plusieurs fois pour le même achat.
**Raison** : Cela se produit généralement lorsque le flow d'achat est déclenché plusieurs fois en raison de problèmes de gestion de l'état de l'interface ou d'interactions rapides de l'utilisateur.
**Solution** : Assurez-vous d'avoir effectué toutes les [étapes de configuration Google Play](initial-android).
## AdaptyError.cantMakePayments en mode observer \{#adaptyerror-cantmakepayments-in-observer-mode\}
**Problème** : Vous obtenez `AdaptyError.cantMakePayments` lors de l'utilisation de `makePurchase` en mode observer.
**Raison** : En mode observer, vous devez gérer les achats de votre côté, et non utiliser la méthode `makePurchase` d'Adapty.
**Solution** : Si vous utilisez `makePurchase` pour les achats, désactivez le mode observer. Vous devez soit utiliser `makePurchase`, soit gérer les achats de votre côté en mode observer. Consultez [Implémenter le mode Observer](implement-observer-mode-android) pour plus de détails.
## Erreur Adapty : (code: 103, message: Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\}
**Problème** : Vous recevez une erreur de facturation indisponible depuis le Google Play Store.
**Raison** : Cette erreur n'est pas liée à Adapty. Il s'agit d'une erreur de la bibliothèque Google Play Billing indiquant que la facturation n'est pas disponible sur l'appareil.
**Solution** : Cette erreur n'est pas liée à Adapty. Vous pouvez en savoir plus dans la documentation du Play Store : [Gérer les codes de réponse BillingResult](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers.
## makePurchasesCompletionHandlers introuvable \{#not-found-makepurchasescompletionhandlers\}
**Problème** : Vous rencontrez des problèmes avec `makePurchasesCompletionHandlers` qui ne sont pas trouvés.
**Raison** : Cela est généralement lié à des problèmes de test en sandbox.
**Solution** : Créez un nouvel utilisateur sandbox et réessayez. Cela résout souvent les problèmes de gestionnaire de fin d'achat liés au sandbox.
## Autres problèmes \{#other-issues\}
**Problème** : Vous rencontrez d'autres problèmes liés aux achats non couverts ci-dessus.
**Solution** : Mettez à jour le SDK vers la dernière version à l'aide des [guides de migration](android-sdk-migration-guides) si nécessaire. De nombreux problèmes sont résolus dans les versions plus récentes du SDK.
---
# File: android-user
---
---
title: "Utilisateurs & accès dans le SDK Android"
description: "Apprenez à gérer les utilisateurs et les niveaux d'accès dans votre application Android avec le SDK Adapty."
---
---
# File: android-identifying-users
---
---
title: "Identifier les utilisateurs dans le SDK Android"
description: "Identifiez les utilisateurs dans Adapty pour améliorer les expériences d'abonnement personnalisées (Android)."
---
Adapty crée un identifiant de profil interne pour chaque utilisateur. Cependant, si vous disposez de votre propre système d'authentification, vous devez définir votre propre Customer User ID. Vous pouvez retrouver les utilisateurs par leur Customer User ID dans la section [Profiles](profiles-crm) et l'utiliser dans l'[API côté serveur](getting-started-with-server-side-api), qui sera transmise à toutes les intégrations.
### Définir le Customer User ID lors de la configuration \{#setting-customer-user-id-on-configuration\}
Si vous disposez d'un identifiant utilisateur au moment de la configuration, passez-le simplement en tant que paramètre `customerUserId` à la méthode `.activate()` :
```kotlin showLineNumbers
Adapty.activate(applicationContext, "PUBLIC_SDK_KEY", customerUserId = "YOUR_USER_ID")
```
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
### Définir le Customer User ID après la configuration \{#setting-customer-user-id-after-configuration\}
Si vous ne disposez pas d'un identifiant utilisateur lors de la configuration du SDK, vous pouvez le définir ultérieurement à tout moment avec la méthode `.identify()`. Les cas d'utilisation les plus courants sont après l'inscription ou la connexion, lorsque l'utilisateur passe du statut d'utilisateur anonyme à celui d'utilisateur authentifié.
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") { error ->
if (error == null) {
// successful identify
}
}
```
```java showLineNumbers
Adapty.identify("YOUR_USER_ID", error -> {
if (error == null) {
// successful identify
}
});
```
Paramètres de la requête :
- **Customer User ID** (obligatoire) : un identifiant utilisateur de type chaîne de caractères.
:::warning
Resoumission des données utilisateur importantes
Dans certains cas, par exemple lorsqu'un utilisateur se reconnecte à son compte, les serveurs d'Adapty disposent déjà d'informations sur cet utilisateur. Dans ces scénarios, le SDK Adapty basculera automatiquement pour travailler avec le nouvel utilisateur. Si vous avez transmis des données à l'utilisateur anonyme, telles que des attributs personnalisés ou des attributions provenant de réseaux tiers, vous devez resoumettre ces données pour l'utilisateur identifié.
Il est également important de noter que vous devez redemander tous les paywalls et produits après avoir identifié l'utilisateur, car les données du nouvel utilisateur peuvent être différentes.
:::
### Déconnexion et reconnexion \{#logging-out-and-logging-in\}
Vous pouvez déconnecter l'utilisateur à tout moment en appelant la méthode `.logout()` :
```kotlin showLineNumbers
Adapty.logout { error ->
if (error == null) {
// successful logout
}
}
```
```java showLineNumbers
Adapty.logout(error -> {
if (error == null) {
// successful logout
}
});
```
Vous pouvez ensuite reconnecter l'utilisateur avec la méthode `.identify()`.
### Détecter les utilisateurs sur plusieurs appareils \{#detect-users-across-devices\}
Lors de l'activation du SDK, il lit automatiquement les droits existants de l'utilisateur depuis StoreKit (iOS) ou Google Play Billing (Android) et les synchronise avec le backend Adapty. Un abonnement actif apparaît sur le profil Adapty sans que l'application n'appelle `restorePurchases`.
Ce qui **ne** se produit **pas** automatiquement, c'est la reconnaissance qu'un profil sur un nouvel appareil appartient au même utilisateur que le profil sur l'appareil d'origine. Adapty fait correspondre les profils par Customer User ID, donc la continuité d'identité dépend de ce que vous utilisez comme CUID.
**Ce qu'Adapty peut détecter entre les appareils**
| Votre configuration | Ce qu'Adapty détecte | Ce que vous devez faire |
| --- | --- | --- |
| Customer User ID = `device_id` (sans connexion à l'application) | Le nouvel appareil reçoit un CUID différent et donc un profil différent. L'abonnement se synchronise avec le nouveau profil via un événement **Access level updated**, mais `subscription_started` ne se déclenche pas — le nouveau profil est traité comme un héritier de l'achat d'origine. Les analyses basées sur `subscription_started` sous-compteront les utilisateurs de retour. | Utilisez un identifiant de compte stable comme Customer User ID pour qu'un utilisateur de retour corresponde au profil existant sur tous les appareils. |
| Customer User ID = identifiant de compte stable (connexion sur chaque appareil) | Le SDK synchronise automatiquement l'abonnement lors de l'appel `activate()`, et `identify()` fait correspondre le profil existant par CUID. | Aucune configuration supplémentaire n'est nécessaire — l'identité et l'abonnement se résolvent automatiquement. |
| Héritier du partage familial Apple | Le membre de la famille reçoit l'abonnement uniquement via un événement **Access level updated** — `subscription_started` ne se déclenche pas. | Écoutez **Access level updated**. Consultez [Apple Family Sharing](apple-family-sharing) pour la matrice complète des événements. |
| Même compte Apple/Google, utilisateurs in-app différents | Le premier profil à enregistrer l'achat devient le parent. Les profils suivants voient l'abonnement via une chaîne d'héritiers, avec un seul événement **Access level updated**. | Exigez une connexion, puis choisissez un [mode de partage](sharing-paid-access-between-user-accounts) adapté à votre modèle. |
**Restaurer les achats sur un nouvel appareil**
Proposez un bouton « Restaurer les achats » initié par l'utilisateur sur votre paywall. Les directives App Review d'Apple (règle 3.1.1) l'exigent, et il sert de solution de secours quand la synchronisation automatique rate un cas limite. Ce bouton doit appeler `restorePurchases` dans votre SDK.
Un appel programmatique à `restorePurchases` au premier lancement n'est pas nécessaire pour une utilisation normale — le SDK effectue déjà l'équivalent lors de l'appel `activate()`. Réservez les appels programmatiques pour forcer une vérification fraîche du reçu, par exemple lors du débogage d'un accès manquant après la fin de `activate()`.
---
# File: android-setting-user-attributes
---
---
title: "Définir les attributs utilisateur dans le SDK Android"
description: "Apprenez à définir les attributs utilisateur dans Adapty pour améliorer la segmentation des audiences."
---
Vous pouvez définir des attributs facultatifs tels que l'e-mail, le numéro de téléphone, etc., pour les utilisateurs de votre application. Vous pouvez ensuite utiliser ces attributs pour créer des [segments](segments) d'utilisateurs ou simplement les consulter dans le CRM.
### Définir les attributs utilisateur \{#setting-user-attributes\}
Pour définir les attributs utilisateur, appelez la méthode `.updateProfile()` :
```kotlin showLineNumbers
val builder = AdaptyProfileParameters.Builder()
.withEmail("email@email.com")
.withPhoneNumber("+18888888888")
.withFirstName("John")
.withLastName("Appleseed")
.withGender(AdaptyProfile.Gender.OTHER)
.withBirthday(AdaptyProfile.Date(1970, 1, 3))
Adapty.updateProfile(builder.build()) { error ->
if (error != null) {
// handle the error
}
}
```
```java showLineNumbers
AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder()
.withEmail("email@email.com")
.withPhoneNumber("+18888888888")
.withFirstName("John")
.withLastName("Appleseed")
.withGender(AdaptyProfile.Gender.OTHER)
.withBirthday(new AdaptyProfile.Date(1970, 1, 3));
Adapty.updateProfile(builder.build(), error -> {
if (error != null) {
// handle the error
}
});
```
Notez que les attributs que vous avez précédemment définis avec la méthode `updateProfile` ne seront pas réinitialisés.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
### Liste des clés autorisées \{#the-allowed-keys-list\}
Les clés `` autorisées pour `AdaptyProfileParameters.Builder` et les valeurs `` correspondantes sont listées ci-dessous :
| Clé | Valeur |
|---|-----|
| email
phoneNumber
firstName
lastName
| String |
| gender | Enum, les valeurs autorisées sont : `female`, `male`, `other` |
| birthday | Date |
### Attributs utilisateur personnalisés \{#custom-user-attributes\}
Vous pouvez définir vos propres attributs personnalisés, généralement liés à l'utilisation de votre application. Par exemple, pour une application de fitness, il peut s'agir du nombre d'exercices par semaine ; pour une application d'apprentissage des langues, du niveau de connaissance de l'utilisateur, etc. Vous pouvez les utiliser dans des segments pour créer des paywalls et des offres ciblées, ainsi que dans les analyses pour déterminer quelles métriques produit ont le plus d'impact sur les revenus.
```kotlin showLineNumbers
builder.withCustomAttribute("key1", "value1")
```
```java showLineNumbers
builder.withCustomAttribute("key1", "value1");
```
Pour supprimer une clé existante, utilisez la méthode `.withRemoved(customAttributeForKey:)` :
```kotlin showLineNumbers
builder.withRemovedCustomAttribute("key2")
```
```java showLineNumbers
builder.withRemovedCustomAttribute("key2");
```
Il peut arriver que vous ayez besoin de connaître les attributs personnalisés déjà définis. Pour cela, utilisez le champ `customAttributes` de l'objet `AdaptyProfile`.
:::warning
Gardez à l'esprit que la valeur de `customAttributes` peut être obsolète, car les attributs utilisateur peuvent être envoyés depuis différents appareils à tout moment. Les attributs sur le serveur ont donc pu être modifiés depuis la dernière synchronisation.
:::
### Limites \{#limits\}
- Jusqu'à 30 attributs personnalisés par utilisateur
- Les noms de clés peuvent comporter jusqu'à 30 caractères. Ils peuvent contenir des caractères alphanumériques ainsi que les caractères suivants : `_` `-` `.`
- La valeur peut être une chaîne de caractères ou un nombre flottant, avec 50 caractères maximum.
---
# File: android-listen-subscription-changes
---
---
title: "Vérifier le statut d'abonnement dans le SDK Android"
description: "Suivez et gérez le statut d'abonnement des utilisateurs dans Adapty pour améliorer la rétention client dans votre application Android."
---
Avec Adapty, suivre le statut d'abonnement est simple. Inutile d'insérer manuellement des identifiants de produits dans votre code. Il suffit de vérifier l'existence d'un [niveau d'accès](access-level) actif pour confirmer le statut d'abonnement d'un utilisateur.
Avant de commencer à vérifier le statut d'abonnement, configurez les [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn).
## Niveau d'accès et objet AdaptyProfile \{#access-level-and-the-adaptyprofile-object\}
Les niveaux d'accès sont des propriétés de l'objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Nous recommandons de récupérer le profil au démarrage de l'application, par exemple lors de l'[identification d'un utilisateur](android-identifying-users#setting-customer-user-id-on-configuration), puis de le mettre à jour à chaque changement. Vous pouvez ainsi utiliser l'objet profil sans avoir à le redemander constamment.
Pour être notifié des mises à jour du profil, écoutez les changements comme décrit dans la section [Écouter les mises à jour du profil, y compris les niveaux d'accès](android-listen-subscription-changes) ci-dessous.
:::tip
Vous souhaitez voir un exemple concret d'intégration du SDK Adapty dans une application mobile ? Consultez nos [exemples d'applications](sample-apps), qui illustrent la configuration complète, notamment l'affichage des paywalls, les achats et d'autres fonctionnalités de base.
:::
## Récupérer le niveau d'accès depuis le serveur \{#retrieving-the-access-level-from-the-server\}
Pour obtenir le niveau d'accès depuis le serveur, utilisez la méthode `.getProfile()` :
```kotlin showLineNumbers
Adapty.getProfile { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
// check the access
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getProfile(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
// check the access
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
Paramètres de la réponse :
| Paramètre | Description |
| --------- | ------------------------------------------------------------ |
| Profile | Un objet [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). En général, il suffit de vérifier le statut du niveau d'accès du profil pour déterminer si l'utilisateur bénéficie d'un accès premium à l'application.
La méthode `.getProfile` fournit le résultat le plus récent, car elle interroge toujours l'API. Si, pour une raison quelconque (par exemple, absence de connexion internet), le SDK Adapty ne parvient pas à récupérer les informations depuis le serveur, les données en cache sont renvoyées. Il est également important de noter que le SDK Adapty met régulièrement à jour le cache `AdaptyProfile` afin de maintenir ces informations aussi récentes que possible.
|
La méthode `.getProfile()` vous fournit le profil utilisateur à partir duquel vous pouvez obtenir le statut du niveau d'accès. Une application peut avoir plusieurs niveaux d'accès. Par exemple, si vous avez une application d'actualités et vendez des abonnements à différentes thématiques indépendamment, vous pouvez créer les niveaux d'accès « sports » et « science ». La plupart du temps, cependant, un seul niveau d'accès suffit — dans ce cas, utilisez simplement le niveau d'accès par défaut « premium ».
Voici un exemple de vérification du niveau d'accès « premium » par défaut :
```kotlin showLineNumbers
Adapty.getProfile { result ->
when (result) {
is AdaptyResult.Success -> {
val profile = result.value
if (profile.accessLevels["premium"]?.isActive == true) {
// grant access to premium features
}
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
```java showLineNumbers
Adapty.getProfile(result -> {
if (result instanceof AdaptyResult.Success) {
AdaptyProfile profile = ((AdaptyResult.Success) result).getValue();
AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("premium");
if (premium != null && premium.isActive()) {
// grant access to premium features
}
} else if (result instanceof AdaptyResult.Error) {
AdaptyError error = ((AdaptyResult.Error) result).getError();
// handle the error
}
});
```
### Écouter les mises à jour du statut d'abonnement \{#listening-for-subscription-status-updates\}
Chaque fois que l'abonnement d'un utilisateur change, Adapty déclenche un événement.
Pour recevoir les messages d'Adapty, une configuration supplémentaire est nécessaire :
```kotlin showLineNumbers
Adapty.setOnProfileUpdatedListener { profile ->
// handle any changes to subscription state
}
```
```java showLineNumbers t
Adapty.setOnProfileUpdatedListener(profile -> {
// handle any changes to subscription state
});
```
Adapty déclenche également un événement au démarrage de l'application. Dans ce cas, le statut d'abonnement mis en cache est transmis.
### Cache du statut d'abonnement \{#subscription-status-cache\}
Le cache intégré au SDK Adapty stocke le statut d'abonnement du profil. Ainsi, même si le serveur est indisponible, les données en cache restent accessibles pour fournir des informations sur le statut d'abonnement du profil.
Il est cependant important de noter que les données ne peuvent pas être demandées directement depuis le cache. Le SDK interroge périodiquement le serveur toutes les minutes pour vérifier s'il y a des mises à jour ou des changements liés au profil. Le cas échéant, les modifications — comme de nouvelles transactions ou d'autres mises à jour — sont transmises aux données en cache afin de les maintenir synchronisées avec le serveur.
---
# File: kids-mode-android
---
---
title: "Mode Enfants dans le SDK Android"
description: "Activez facilement le Mode Enfants pour respecter les politiques Google. Ni GAID ni données publicitaires collectées dans le SDK Android."
---
Si votre application Android est destinée aux enfants, vous devez suivre les politiques de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si vous utilisez le SDK Adapty, quelques étapes simples vous permettront de le configurer pour respecter ces politiques et passer les revues de l'app store.
## Ce qui est requis \{#whats-required\}
Vous devez configurer le SDK Adapty pour désactiver la collecte :
- de l'[Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248)
- de l'[adresse IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf)
De plus, nous recommandons d'utiliser l'identifiant utilisateur client avec précaution. Un identifiant au format `` sera immanquablement considéré comme une collecte de données personnelles, tout comme l'utilisation d'un e-mail. Pour le Mode Enfants, la bonne pratique consiste à utiliser des identifiants aléatoires ou anonymisés (par exemple, des identifiants hachés ou des UUID générés par l'appareil) pour garantir la conformité.
## Activation du Mode Enfants \{#enabling-kids-mode\}
### Modifications dans l'Adapty Dashboard \{#updates-in-the-adapty-dashboard\}
Dans l'Adapty Dashboard, vous devez désactiver la collecte des adresses IP. Pour ce faire, rendez-vous dans [App settings](https://app.adapty.io/settings/general) et cliquez sur **Disable IP address collection** sous **Collect users' IP address**.
### Modifications dans le code de votre application mobile \{#updates-in-your-mobile-app-code\}
Pour respecter les politiques, vous devez désactiver la collecte de l'Android Advertising ID (AAID/GAID) et de l'adresse IP lors de l'initialisation du SDK Adapty :
**Kotlin :**
```kotlin showLineNumbers
override fun onCreate() {
super.onCreate()
Adapty.activate(
applicationContext,
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
// highlight-start
.withAdIdCollectionDisabled(true) // set to `true`
.withIpAddressCollectionDisabled(true) // set to `true`
// highlight-end
.build()
)
}
```
**Java :**
```java showLineNumbers
@Override
public void onCreate() {
super.onCreate();
Adapty.activate(
applicationContext,
new AdaptyConfig.Builder("PUBLIC_SDK_KEY")
// highlight-start
.withAdIdCollectionDisabled(true) // set to `true`
.withIpAddressCollectionDisabled(true) // set to `true`
// highlight-end
.build()
);
}
```
### Modifications dans votre manifeste Android \{#updates-in-your-android-manifest\}
:::note
Si votre application cible **uniquement** les enfants et se compile avec Android 13 (API 33) ou supérieur, Google Play exige que vous ne demandiez pas la permission `AD_ID`. Un autre SDK dans votre application (analytics, attribution ou publicité) peut ajouter cette permission via la fusion de manifestes. Définir `withAdIdCollectionDisabled(true)` empêche Adapty de collecter l'identifiant, mais ne supprime pas une permission déclarée par un autre SDK.
:::
Pour supprimer la permission, ajoutez ce qui suit à l'intérieur de l'élément `` du fichier `app/src/main/AndroidManifest.xml`. L'élément `` doit déclarer `xmlns:tools="http://schemas.android.com/tools"`.
```xml showLineNumbers title="AndroidManifest.xml"
```
---
# File: android-onboardings
---
---
title: "Onboardings dans le SDK Android"
description: "Découvrez comment travailler avec les onboardings dans votre application Android avec le SDK Adapty."
---
:::tip
**À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une apparence Android cohérente, des temps de chargement plus rapides et aucune dépendance à l'environnement WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour commencer.
:::
---
# File: android-get-onboardings
---
---
title: "Récupérer les onboardings dans le SDK Android"
description: "Apprenez à récupérer les onboardings dans Adapty pour Android."
---
:::tip
**À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu cohérent avec Android, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Récupérer les flows et paywalls](android-get-pb-paywalls) et [Afficher les flows et paywalls](android-present-paywalls) pour démarrer.
:::
Après avoir [conçu la partie visuelle de votre onboarding](design-onboarding) avec le builder dans l'Adapty Dashboard, vous pouvez l'afficher dans votre application Android. La première étape consiste à récupérer l'onboarding associé au placement et sa configuration d'affichage, comme décrit ci-dessous.
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou supérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
## Récupérer un onboarding \{#fetch-onboarding\}
Lorsque vous créez un [onboarding](onboardings) avec notre builder no-code, il est stocké sous forme de conteneur avec une configuration que votre application doit récupérer et afficher. Ce conteneur gère l'intégralité de l'expérience : quel contenu s'affiche, comment il est présenté et comment les interactions utilisateur (comme les réponses à un quiz ou les saisies de formulaire) sont traitées. Le conteneur suit également automatiquement les événements analytiques, vous n'avez donc pas besoin d'implémenter un suivi séparé des vues.
Pour de meilleures performances, récupérez la configuration de l'onboarding tôt afin de laisser suffisamment de temps aux images pour se télécharger avant de les afficher aux utilisateurs.
Pour récupérer un onboarding, utilisez la méthode `getOnboarding` :
```kotlin showLineNumbers
Adapty.getOnboarding("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val onboarding = result.value
// the requested onboarding
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **placementId** | requis | L'identifiant du [placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc safe de l'utiliser pendant la session pour éviter des requêtes réseau.
Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les onboardings localement sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système garantit que vous obtenez toujours la dernière version de vos onboardings, même en cas de connexion internet limitée.
|
| **loadTimeout** | par défaut : 5 s | Cette valeur limite le délai d'attente de cette méthode. Si le délai est atteint, les données en cache ou le fallback local sont renvoyés.
Notez que dans de rares cas, cette méthode peut dépasser légèrement le délai spécifié dans `loadTimeout`, car l'opération peut impliquer plusieurs requêtes en interne.
Pour Android : vous pouvez créer un `TimeInterval` avec des fonctions d'extension (comme `5.seconds`, où `.seconds` provient de `import com.adapty.utils.seconds`), ou `TimeInterval.seconds(5)`. Pour ne pas définir de limite, utilisez `TimeInterval.INFINITE`.
|
Paramètres de la réponse :
| Paramètre | Description |
|:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| Onboarding | Un objet [`AdaptyOnboarding`](https://android.adapty.io/adapty/com.adapty.models/-adapty-onboarding/) contenant : l'identifiant et la configuration de l'onboarding, le Remote Config et plusieurs autres propriétés. |
## Accélérer la récupération de l'onboarding avec l'onboarding de l'audience par défaut \{#speed-up-onboarding-fetching-with-default-audience-onboarding\}
En général, les onboardings sont récupérés presque instantanément, vous n'avez donc pas à vous soucier d'optimiser ce processus. Cependant, si vous avez de nombreuses audiences et onboardings et que vos utilisateurs ont une connexion internet faible, la récupération d'un onboarding peut prendre plus de temps que souhaité. Dans ce cas, vous pouvez afficher un onboarding par défaut pour garantir une expérience utilisateur fluide plutôt que de ne rien afficher.
Pour cela, vous pouvez utiliser la méthode `getOnboardingForDefaultAudience`, qui récupère l'onboarding du placement spécifié pour l'audience **All Users**. Il est toutefois essentiel de comprendre que l'approche recommandée reste de récupérer l'onboarding avec la méthode `getOnboarding`, comme décrit dans la section [Récupérer un onboarding](#fetch-onboarding) ci-dessus.
:::warning
Préférez `getOnboarding` à `getOnboardingForDefaultAudience`, car cette dernière présente des limitations importantes :
- **Problèmes de compatibilité** : peut créer des difficultés lors de la prise en charge de plusieurs versions de l'application, nécessitant soit des designs rétrocompatibles, soit d'accepter que les anciennes versions puissent s'afficher incorrectement.
- **Aucune personnalisation** : affiche uniquement le contenu pour l'audience "All Users", sans ciblage basé sur le pays, l'attribution ou les attributs personnalisés.
Si la récupération plus rapide l'emporte sur ces inconvénients pour votre cas d'usage, utilisez `getOnboardingForDefaultAudience` comme indiqué ci-dessous. Sinon, utilisez `getOnboarding` comme décrit [ci-dessus](#fetch-onboarding).
:::
```kotlin
Adapty.getOnboardingForDefaultAudience("YOUR_PLACEMENT_ID") { result ->
when (result) {
is AdaptyResult.Success -> {
val onboarding = result.value
// Handle successful onboarding retrieval
}
is AdaptyResult.Error -> {
val error = result.error
// Handle error case
}
}
}
```
Paramètres :
| Paramètre | Présence | Description |
|---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **placementId** | requis | L'identifiant du [placement](placements) souhaité. Il s'agit de la valeur que vous avez indiquée lors de la création d'un placement dans l'Adapty Dashboard. |
| **locale** | optionnel
par défaut : `en`
| L'identifiant de la localisation de l'onboarding. Ce paramètre doit être un code de langue composé d'un ou deux sous-tags séparés par le caractère moins (**-**). Le premier sous-tag correspond à la langue, le second à la région.
Exemple : `en` signifie anglais, `pt-br` représente le portugais brésilien.
Consultez [Localisations et codes de langue](localizations-and-locale-codes) pour plus d'informations sur les codes de langue et nos recommandations d'utilisation.
|
| **fetchPolicy** | par défaut : `.reloadRevalidatingCacheData` | Par défaut, le SDK tente de charger les données depuis le serveur et renvoie les données en cache en cas d'échec. Nous recommandons cette option car elle garantit que vos utilisateurs obtiennent toujours les données les plus récentes.
Cependant, si vos utilisateurs ont une connexion internet instable, envisagez d'utiliser `.returnCacheDataElseLoad` pour renvoyer les données en cache si elles existent. Dans ce cas, les utilisateurs pourraient ne pas obtenir les toutes dernières données, mais bénéficieront de temps de chargement plus rapides, quelle que soit la qualité de leur connexion. Le cache est mis à jour régulièrement, il est donc safe de l'utiliser pendant la session pour éviter des requêtes réseau.
Notez que le cache est conservé au redémarrage de l'application et n'est effacé que lors d'une réinstallation ou d'un nettoyage manuel.
Le SDK Adapty stocke les onboardings localement sur deux niveaux : le cache mis à jour régulièrement décrit ci-dessus et les onboardings de secours. Nous utilisons également un CDN pour récupérer les onboardings plus rapidement et un serveur de secours indépendant si le CDN est inaccessible. Ce système garantit que vous obtenez toujours la dernière version de vos onboardings, même en cas de connexion internet limitée.
|
---
# File: android-present-onboardings
---
---
title: "Présenter les onboardings dans le SDK Android"
description: "Apprenez à présenter les onboardings sur Android pour un engagement utilisateur efficace."
---
:::tip
**À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows se rendent nativement sur l'appareil — vous offrant des animations plus fluides, un look and feel Android cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir les flows et paywalls](android-get-pb-paywalls) et [Afficher les flows et paywalls](android-present-paywalls) pour commencer.
:::
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou ultérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
Si vous avez personnalisé un onboarding avec l'Onboarding Builder, vous n'avez pas à vous soucier de son rendu dans votre code d'application mobile pour l'afficher à l'utilisateur. Un tel onboarding contient à la fois ce qui doit être affiché et comment il doit l'être.
Pour afficher l'onboarding visuel à l'écran de l'appareil, vous devez d'abord le configurer. Pour ce faire, appelez la méthode `AdaptyUI.getOnboardingView()` ou créez directement le `OnboardingView` :
```kotlin
val onboardingView = AdaptyUI.getOnboardingView(
activity = this,
viewConfig = onboardingConfig,
eventListener = eventListener
)
```
```kotlin
val onboardingView = AdaptyOnboardingView(activity)
onboardingView.show(
viewConfig = onboardingConfig,
delegate = eventListener
)
```
```java
AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView(
activity,
onboardingConfig,
eventListener
);
```
```java
AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity);
onboardingView.show(onboardingConfig, eventListener);
```
```xml
```
Une fois la vue créée avec succès, vous pouvez l'ajouter à la hiérarchie de vues et l'afficher à l'écran de l'appareil.
Paramètres de la requête :
| Paramètre | Présence | Description |
| :-------- | :------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **viewConfig** | requis | La configuration d'onboarding obtenue depuis `AdaptyUI.getOnboardingConfiguration()` |
| **eventListener** | requis | Une implémentation de `AdaptyOnboardingEventListener` pour gérer les événements d'onboarding. Consultez [Gestion des événements d'onboarding](android-handle-onboarding-events) pour plus de détails. |
## Modifier la couleur de l'indicateur de chargement \{#change-loading-indicator-color\}
Vous pouvez remplacer la couleur par défaut de l'indicateur de chargement de la façon suivante :
```xml
```
## Ajouter des transitions fluides entre l'écran de démarrage et l'onboarding \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\}
Par défaut, entre l'écran de démarrage et l'onboarding, vous verrez l'écran de chargement jusqu'à ce que l'onboarding soit entièrement chargé. Si vous souhaitez rendre la transition plus fluide, vous pouvez la personnaliser et soit prolonger l'écran de démarrage, soit afficher autre chose.
Pour ce faire, créez `adapty_onboarding_placeholder_view.xml` dans `res/layout` et définissez-y un placeholder (ce qui sera affiché pendant le chargement de l'onboarding).
Si vous définissez un placeholder, l'onboarding sera chargé en arrière-plan et affiché automatiquement une fois prêt.
## Désactiver les marges de zone sécurisée \{#disable-safe-area-paddings\}
Par défaut, la vue d'onboarding applique automatiquement des marges de zone sécurisée pour éviter les éléments d'interface système comme la barre d'état et la barre de navigation. Si vous souhaitez désactiver ce comportement et avoir un contrôle total sur la mise en page, vous pouvez le faire en définissant le paramètre `safeAreaPaddings` sur `false`.
```kotlin
val onboardingView = AdaptyUI.getOnboardingView(
activity = this,
viewConfig = onboardingConfig,
eventListener = eventListener,
safeAreaPaddings = false
)
```
```kotlin
val onboardingView = AdaptyOnboardingView(activity)
onboardingView.show(
viewConfig = onboardingConfig,
delegate = eventListener,
safeAreaPaddings = false
)
```
```java
AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView(
activity,
onboardingConfig,
eventListener,
false
);
```
```java
AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity);
onboardingView.show(onboardingConfig, eventListener, false);
```
Vous pouvez également contrôler ce comportement globalement en ajoutant une ressource booléenne à votre application :
```xml
false
```
Lorsque `safeAreaPaddings` est défini sur `false`, l'onboarding s'étend sur tout l'écran sans ajustement automatique des marges, vous donnant un contrôle total sur la mise en page et permettant au contenu de l'onboarding d'utiliser tout l'espace de l'écran.
## Personnaliser l'ouverture des liens dans les onboardings \{#customize-how-links-open-in-onboardings\}
:::important
La personnalisation de l'ouverture des liens dans les onboardings est prise en charge à partir du SDK Adapty v3.15.1.
:::
Par défaut, les liens dans les onboardings s'ouvrent dans un navigateur intégré à l'application. Cela offre une expérience utilisateur fluide en affichant les pages web au sein de votre application, permettant aux utilisateurs de les consulter sans changer d'application.
Si vous préférez ouvrir les liens dans un navigateur externe, vous pouvez personnaliser ce comportement en définissant le paramètre `externalUrlsPresentation` sur `AdaptyWebPresentation.ExternalBrowser` :
```kotlin
val onboardingConfig = AdaptyUI.getOnboardingConfiguration(
onboarding = onboarding,
externalUrlsPresentation = AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser
)
```
```java
AdaptyOnboardingConfiguration onboardingConfig = AdaptyUI.getOnboardingConfiguration(
onboarding,
AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser
);
```
---
# File: android-handle-onboarding-events
---
---
title: "Gérer les événements d'onboarding dans le SDK Android"
description: "Gérez les événements liés à l'onboarding sous Android avec Adapty."
---
:::tip
**À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, une apparence cohérente avec Android, des temps de chargement réduits et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour commencer.
:::
Avant de commencer, assurez-vous que :
1. Vous avez installé le [SDK Adapty Android](sdk-installation-android) version 3.8.0 ou ultérieure.
2. Vous avez [créé un onboarding](create-onboarding).
3. Vous avez ajouté l'onboarding à un [placement](placements).
Les onboardings configurés avec le builder génèrent des événements auxquels votre application peut réagir. Découvrez comment y répondre ci-dessous.
Pour contrôler ou surveiller les processus qui se produisent sur l'écran d'onboarding dans votre application Android, implémentez l'interface `AdaptyOnboardingEventListener`.
## Actions personnalisées \{#custom-actions\}
Dans le builder, vous pouvez ajouter une action **custom** à un bouton et lui attribuer un ID. Vous pouvez ensuite utiliser cet ID dans votre code et le traiter comme une action personnalisée.
Par exemple, si un utilisateur appuie sur un bouton personnalisé comme **Login** ou **Allow notifications**, la méthode delegate `onCustomAction` sera déclenchée avec l'ID d'action défini dans le builder. Vous pouvez créer vos propres IDs, comme « allowNotifications ».
```kotlin showLineNumbers
class YourActivity : AppCompatActivity() {
private val eventListener = object : AdaptyOnboardingEventListener {
override fun onCustomAction(action: AdaptyOnboardingCustomAction, context: Context) {
when (action.actionId) {
"allowNotifications" -> {
// Request notification permissions
}
}
}
override fun onError(error: AdaptyOnboardingError, context: Context) {
// Handle errors
}
// ... other required delegate methods
}
}
```
Exemple d'événement (Cliquer pour développer)
```json
{
"actionId": "allowNotifications",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
}
}
```
## Fermeture de l'onboarding \{#closing-onboarding\}
L'onboarding est considéré comme fermé lorsqu'un utilisateur appuie sur un bouton avec l'action **Close** assignée. Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple :
:::important
Vous devez gérer ce qui se passe lorsqu'un utilisateur ferme l'onboarding. Par exemple, vous devez arrêter d'afficher l'onboarding lui-même.
:::
Par exemple :
```kotlin
override fun onCloseAction(action: AdaptyOnboardingCloseAction, context: Context) {
// Dismiss the onboarding screen
(context as? Activity)?.onBackPressed()
}
```
Exemple d'événement (Cliquer pour développer)
```json
{
"action_id": "close_button",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "final_screen",
"screen_index": 3,
"total_screens": 4
}
}
```
## Ouverture d'un paywall \{#opening-a-paywall\}
:::tip
Gérez cet événement pour ouvrir un paywall si vous souhaitez l'afficher à l'intérieur de l'onboarding. Si vous voulez ouvrir un paywall après sa fermeture, il existe une approche plus directe — gérez [`AdaptyOnboardingCloseAction`](#closing-onboarding) et ouvrez le paywall sans vous appuyer sur les données de l'événement.
:::
La manière la plus fluide de travailler avec les paywalls dans les onboardings est de rendre l'ID d'action égal à l'ID de placement du paywall. Ainsi, après l'`AdaptyOnboardingOpenPaywallAction`, vous pouvez utiliser l'ID de placement pour récupérer et ouvrir le paywall directement :
```kotlin
override fun onOpenPaywallAction(action: AdaptyOnboardingOpenPaywallAction, context: Context) {
// Get the paywall using the placement ID from the action
Adapty.getPaywall(placementId = action.actionId) { result ->
when (result) {
is AdaptyResult.Success -> {
val paywall = result.value
// Get the paywall configuration
AdaptyUI.getViewConfiguration(paywall) { result ->
when(result) {
is AdaptyResult.Success -> {
val paywallConfig = result.value
// Create and present the paywall
val paywallView = AdaptyUI.getPaywallView(
activity = this,
viewConfig = paywallConfig,
products,
eventListener = paywallEventListener
)
// Add the paywall view to your layout
binding.container.addView(paywallView)
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
is AdaptyResult.Error -> {
val error = result.error
// handle the error
}
}
}
}
```
Exemple d'événement (Cliquer pour développer)
```json
{
"action_id": "premium_offer_1",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "pricing_screen",
"screen_index": 2,
"total_screens": 4
}
}
```
## Fin du chargement de l'onboarding \{#finishing-loading-onboarding\}
Lorsqu'un onboarding termine son chargement, cette méthode est invoquée :
```kotlin
override fun onFinishLoading(action: AdaptyOnboardingLoadedAction, context: Context) {
// Handle loading completion
}
```
Exemple d'événement (Cliquer pour développer)
```json
{
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "welcome_screen",
"screen_index": 0,
"total_screens": 4
}
}
```
## Événements de navigation \{#navigation-events\}
La méthode `onAnalyticsEvent` est appelée lorsque différents événements analytiques se produisent au cours du flow d'onboarding.
L'objet `event` peut être de l'un des types suivants :
|Type | Description |
|------------|-------------|
| `OnboardingStarted` | Lorsque l'onboarding a été chargé |
| `ScreenPresented` | Lorsqu'un écran est affiché |
| `ScreenCompleted` | Lorsqu'un écran est complété. Inclut un `elementId` optionnel (identifiant de l'élément complété) et une `reply` optionnelle (réponse de l'utilisateur). Déclenché lorsque les utilisateurs effectuent une action pour quitter l'écran. |
| `SecondScreenPresented` | Lorsque le deuxième écran est affiché |
| `UserEmailCollected` | Déclenché lorsque l'adresse e-mail de l'utilisateur est collectée via le champ de saisie |
| `OnboardingCompleted` | Déclenché lorsqu'un utilisateur atteint un écran avec l'ID `final`. Si vous avez besoin de cet événement, attribuez l'ID `final` au dernier écran. |
| `Unknown` | Pour tout type d'événement non reconnu. Inclut `name` (le nom de l'événement inconnu) et `meta` (métadonnées supplémentaires) |
Chaque événement inclut des informations `meta` contenant :
| Champ | Description |
|------------|-------------|
| `onboardingId` | Identifiant unique du flow d'onboarding |
| `screenClientId` | Identifiant de l'écran actuel |
| `screenIndex` | Position de l'écran actuel dans le flow |
| `totalScreens` | Nombre total d'écrans dans le flow |
Voici un exemple d'utilisation des événements analytiques pour le suivi :
```kotlin
override fun onAnalyticsEvent(event: AdaptyOnboardingAnalyticsEvent, context: Context) {
when (event) {
is AdaptyOnboardingAnalyticsEvent.OnboardingStarted -> {
// Track onboarding start
trackEvent("onboarding_started", event.meta)
}
is AdaptyOnboardingAnalyticsEvent.ScreenPresented -> {
// Track screen presentation
trackEvent("screen_presented", event.meta)
}
is AdaptyOnboardingAnalyticsEvent.ScreenCompleted -> {
// Track screen completion with user response
trackEvent("screen_completed", event.meta, event.elementId, event.reply)
}
is AdaptyOnboardingAnalyticsEvent.OnboardingCompleted -> {
// Track successful onboarding completion
trackEvent("onboarding_completed", event.meta)
}
is AdaptyOnboardingAnalyticsEvent.Unknown -> {
// Handle unknown events
trackEvent(event.name, event.meta)
}
// Handle other cases as needed
}
}
```
Exemples d'événements (Cliquer pour développer)
```javascript
// OnboardingStarted
{
"name": "onboarding_started",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "welcome_screen",
"screen_index": 0,
"total_screens": 4
}
}
// ScreenPresented
{
"name": "screen_presented",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "interests_screen",
"screen_index": 2,
"total_screens": 4
}
}
// ScreenCompleted
{
"name": "screen_completed",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
},
"params": {
"element_id": "profile_form",
"reply": "success"
}
}
// SecondScreenPresented
{
"name": "second_screen_presented",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
}
}
// UserEmailCollected
{
"name": "user_email_collected",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
}
}
// OnboardingCompleted
{
"name": "onboarding_completed",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "final_screen",
"screen_index": 3,
"total_screens": 4
}
}
```
---
# File: android-onboarding-input
---
---
title: "Traiter les données des onboardings dans le SDK Android"
description: "Enregistrez et utilisez les données des onboardings dans votre application Android avec le SDK Adapty."
---
:::tip
**À partir du SDK v4**, vous pouvez créer des [flows](android-get-pb-paywalls) comme alternative plus puissante aux onboardings. Contrairement aux onboardings qui s'exécutent dans une WebView, les flows s'affichent nativement sur l'appareil — offrant des animations plus fluides, un rendu Android cohérent, des temps de chargement plus rapides et aucune dépendance au runtime WebView. Consultez [Obtenir des flows et paywalls](android-get-pb-paywalls) et [Afficher des flows et paywalls](android-present-paywalls) pour démarrer.
:::
Lorsque vos utilisateurs répondent à une question de quiz ou saisissent des données dans un champ de saisie, la méthode `onStateUpdatedAction` est invoquée. Vous pouvez enregistrer ou traiter le type de champ dans votre code.
Par exemple :
```kotlin
override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) {
// Store user preferences or responses
when (val params = action.params) {
is AdaptyOnboardingStateUpdatedParams.Select -> {
// Handle single selection
}
is AdaptyOnboardingStateUpdatedParams.MultiSelect -> {
// Handle multiple selections
}
is AdaptyOnboardingStateUpdatedParams.Input -> {
// Handle text input
}
is AdaptyOnboardingStateUpdatedParams.DatePicker -> {
// Handle date selection
}
}
}
```
Consultez le format de l'action [ici](https://android.adapty.io/adapty-ui/com.adapty.ui.onboardings.actions/-adapty-onboarding-state-updated-action/).
Exemples de données enregistrées (le format peut différer selon votre implémentation)
```javascript
// Example of a saved select action
{
"elementId": "preference_selector",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "preferences_screen",
"screenIndex": 1,
"screensTotal": 3
},
"params": {
"type": "select",
"value": {
"id": "option_1",
"value": "premium",
"label": "Premium Plan"
}
}
}
// Example of a saved multi-select action
{
"elementId": "interests_selector",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "interests_screen",
"screenIndex": 2,
"screensTotal": 3
},
"params": {
"type": "multiSelect",
"value": [
{
"id": "interest_1",
"value": "sports",
"label": "Sports"
},
{
"id": "interest_2",
"value": "music",
"label": "Music"
}
]
}
}
// Example of a saved input action
{
"elementId": "name_input",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
},
"params": {
"type": "input",
"value": {
"type": "text",
"value": "John Doe"
}
}
}
// Example of a saved date picker action
{
"elementId": "birthday_picker",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
},
"params": {
"type": "datePicker",
"value": {
"day": 15,
"month": 6,
"year": 1990
}
}
}
```
## Cas d'usage \{#use-cases\}
### Enrichir les profils utilisateurs avec des données \{#enrich-user-profiles-with-data\}
Si vous souhaitez associer immédiatement les données saisies au profil utilisateur et éviter de leur demander deux fois les mêmes informations, vous devez [mettre à jour le profil utilisateur](android-setting-user-attributes) avec les données saisies lors du traitement de l'action.
Par exemple, vous demandez aux utilisateurs de saisir leur nom dans le champ texte avec l'ID `name`, et vous souhaitez définir la valeur de ce champ comme prénom de l'utilisateur. Vous leur demandez également de saisir leur e-mail dans le champ `email`. Dans votre code, cela peut ressembler à ceci :
```kotlin showLineNumbers
override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) {
// Store user preferences or responses
when (val params = action.params) {
is AdaptyOnboardingStateUpdatedParams.Input -> {
// Handle text input
val builder = AdaptyProfileParameters.Builder()
// Map elementId to appropriate profile field
when (action.elementId) {
"name" -> {
when (val inputParams = params.params) {
is AdaptyOnboardingInputParams.Text -> {
builder.withFirstName(inputParams.value)
}
}
}
"email" -> {
when (val inputParams = params.params) {
is AdaptyOnboardingInputParams.Email -> {
builder.withEmail(inputParams.value)
}
}
}
}
Adapty.updateProfile(builder.build()) { error ->
if (error != null) {
// handle the error
}
}
}
}
}
```
### Personnaliser les paywalls en fonction des réponses \{#customize-paywalls-based-on-answers\}
Grâce aux quiz dans les onboardings, vous pouvez également personnaliser les paywalls affichés aux utilisateurs après qu'ils ont terminé l'onboarding.
Par exemple, vous pouvez interroger les utilisateurs sur leur expérience sportive et afficher des CTA et des produits différents selon les groupes d'utilisateurs.
1. [Ajoutez un quiz](onboarding-quizzes) dans le constructeur d'onboarding et attribuez des IDs significatifs à ses options.
2. Traitez les réponses au quiz en fonction de leurs IDs et [définissez des attributs personnalisés](android-setting-user-attributes) pour les utilisateurs.
```kotlin showLineNumbers
override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) {
// Handle quiz responses and set custom attributes
when (val params = action.params) {
is AdaptyOnboardingStateUpdatedParams.Select -> {
// Handle quiz selection
val builder = AdaptyProfileParameters.Builder()
// Map quiz responses to custom attributes
when (action.elementId) {
"experience" -> {
// Set custom attribute 'experience' with the selected value (beginner, amateur, pro)
builder.withCustomAttribute("experience", params.params.value)
}
}
Adapty.updateProfile(builder.build()) { error ->
if (error != null) {
// handle the error
}
}
}
}
}
```
3. [Créez des segments](segments) pour chaque valeur d'attribut personnalisé.
4. Créez un [placement](placements) et ajoutez des [audiences](audience) pour chaque segment créé.
5. [Affichez un paywall](android-paywalls) pour le placement dans le code de votre application. Si votre onboarding comporte un bouton qui ouvre un paywall, implémentez le code du paywall comme [réponse à l'action de ce bouton](android-handle-onboarding-events#opening-a-paywall).
---
# File: android-best-practices
---
---
title: "Bonnes pratiques avec le SDK Android"
description: "Modèles de référence pour intégrer le SDK Adapty sur Android — ordre des appels, gestion des erreurs et autres règles de préparation à la production."
---
---
# File: android-sdk-call-order
---
---
title: "Ordre des appels dans le SDK Android"
description: "Évitez la perte d'accès premium, les attributions manquantes et les erreurs ADAPTY_NOT_INITIALIZED intermittentes en appelant les méthodes du SDK Adapty dans le bon ordre."
---
`Adapty.activate()` doit se terminer avant tout autre appel à une méthode du SDK Adapty. Tant qu'il n'est pas terminé, le SDK n'a aucun état. Tout appel émis avant ou en parallèle de `activate()` échoue avec [`ADAPTY_NOT_INITIALIZED`](android-sdk-error-handling).
Si votre application authentifie les utilisateurs et que vous récupérez un identifiant utilisateur client après le lancement, appelez `Adapty.identify()` à ce moment-là. N'appelez pas de méthodes liées aux actions utilisateur avant que le callback de fin d'`identify` ne se déclenche. Les appels qui s'exécutent en concurrence avec lui retournent soit une erreur dans leur callback, soit atterrissent sur le profil anonyme créé à l'activation. Dans ce cas, l'attribution, les identifiants MMP comme `appsflyer_id`, et la propriété de l'installation ne sont pas toujours transférés vers le profil identifié. Si votre application n'authentifie pas les utilisateurs, ignorez `identify` et continuez à travailler avec le profil anonyme.
Les SDK MMP et d'analytique (AppsFlyer, Adjust, Branch, PostHog) suivent la même règle. Initialisez-les en premier et attendez leurs callbacks d'UID avant d'appeler `Adapty.activate`. Sinon, l'identifiant MMP atterrit sur un profil anonyme éphémère et n'est pas toujours transféré vers le profil identifié. Pour les spécificités d'AppsFlyer, consultez [AppsFlyer](appsflyer).
## Le bon ordre \{#the-correct-order\}
Votre parcours dépend de deux éléments : quand vous connaissez l'identifiant utilisateur client, et si vous utilisez un SDK MMP ou d'analytique.
- **Étapes 2 et 5** : Obligatoires pour toutes les applications. Activez le SDK, puis appelez les méthodes du SDK.
- **Étapes 1 et 3** : Requises uniquement si vous intégrez un SDK MMP ou d'analytique (AppsFlyer, Adjust, Branch, PostHog).
- **Étape 4** : Requise uniquement si votre application authentifie les utilisateurs et récupère l'identifiant utilisateur client après le lancement.
Si vous disposez de l'identifiant utilisateur client au lancement de l'application, passez-le dans `AdaptyConfig.Builder` avant d'appeler `activate()` (étape 2a). Ce chemin ne crée jamais de profil anonyme, l'étape 4 est donc inutile.
| Étape | Appel | Quand | Notes |
|-------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| 1 | Initialisez votre SDK MMP ou d'analytique (AppsFlyer, Adjust, PostHog, Branch) | Lancement de l'app, en premier | Attendez le callback d'UID du MMP, par exemple `getAppsFlyerUID`. |
| 2a | `Adapty.activate(context, AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | Lancement de l'app, après l'étape 1, si vous disposez de l'identifiant utilisateur client | Recommandé. Aucun profil anonyme n'est jamais créé. |
| 2b | `Adapty.activate(context, AdaptyConfig.Builder("KEY").build())` sans `customerUserId` | Lancement de l'app, après l'étape 1, si vous ne disposez pas de l'identifiant utilisateur client (ou ne le collectez jamais) | Adapty crée un profil anonyme. |
| 3 | `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` pour chaque MMP | Après l'étape 2, avant tout appel lié à une action utilisateur | Requis pour que les identifiants MMP atterrissent sur le bon profil. |
| 4 | `Adapty.identify("YOUR_USER_ID") { error -> ... }` | Après l'étape 3 (ou l'étape 2 si pas de MMP), avant l'étape 5 — uniquement sur le chemin 2b avec authentification | Utilisez le callback de fin. Les appels concurrents pendant `identify` peuvent atterrir sur le profil anonyme. |
| 5 | `getPaywall`, `getPaywallProducts`, `restorePurchases`, `makePurchase`, `updateAttribution`, `updateProfile` | Après l'étape 4 si vous appelez `identify` ; sinon après l'étape 3 (ou l'étape 2 si pas de MMP) | Ces appels nécessitent un profil stable. |
:::important
Ignorer ces étapes entraîne la perte d'accès premium pour les utilisateurs existants, l'absence d'`appsflyer_id` sur les profils, et des paywalls retournés pour la mauvaise audience.
:::
## Installations web2app et web-funnel \{#web2app-and-web-funnel-installs\}
Si des utilisateurs achètent via un paiement web (Stripe, Paddle) et installent ensuite l'application native, le premier `activate()` de l'appareil crée un nouveau profil anonyme. Ce profil n'est pas lié au profil web. Si vous pouvez résoudre l'identifiant utilisateur client avant le lancement de l'application (depuis votre flux d'authentification ou le referrer d'installation), passez-le directement dans `AdaptyConfig.Builder`. Sinon, l'achat web est invisible sur l'appareil jusqu'à ce que vous appeliez `identify("YOUR_USER_ID")` puis `restorePurchases`.
Pour les métadonnées à envoyer avec chaque paiement web, consultez :
- [Stripe](stripe)
- [Paddle](paddle)
---
# File: android-optimize-paywall-fetching
---
---
title: "Optimiser la récupération des paywalls dans le SDK Android"
description: "Récupérez les paywalls Adapty de manière fiable : timing, mise en cache et patterns de secours pour Android."
---
Une récupération fiable de paywall sur Android repose sur trois éléments : un affichage rapide, le renvoi du paywall ciblé par audience, et un repli gracieux lorsque le réseau est lent. Les règles ci-dessous couvrent le timing, la mise en cache et les patterns de secours pour y parvenir.
:::tip
Ces règles supposent que `Adapty.activate()` et `Adapty.identify()` ont déjà été résolus. Voir [Ordre d'appel dans le SDK Android](android-sdk-call-order).
:::
## Règles et pièges à éviter \{#rules-and-pitfalls\}
| À faire | À éviter | Pourquoi |
|---|---|---|
| Récupérez le placement que vous êtes sur le point d'afficher. | Pré-charger tous les placements en parallèle au démarrage. | Le pré-chargement en masse bloque le thread principal et provoque un écran noir pendant le pic de requêtes. |
| Appelez `getPaywall` après que l'attribution a eu le temps de se résoudre — par exemple, 1 à 2 secondes après `activate` ou après le déclenchement de `setOnProfileUpdatedListener`. | Appeler `getPaywall` dans `Application.onCreate()`. | L'attribution n'est pas encore disponible. Le paywall se résout contre l'audience par défaut et contourne silencieusement les segments et la personnalisation ASA. |
| Définissez un `loadTimeout` et configurez un [paywall de secours](fallback-paywalls) pour chaque placement. | Attendre indéfiniment que `getPaywall` réponde. | Sans timeout, les utilisateurs avec une mauvaise connexion voient un écran vide jusqu'à ce que le réseau réponde — ou ferment l'application. |
Consultez [Récupérer les paywalls et les produits](fetch-paywalls-and-products-android) pour la référence des paramètres `fetchPolicy` et `loadTimeout`, et [Placements](placements) pour choisir le bon placement.
## Optimiser pour les connexions lentes \{#tune-for-poor-connectivity\}
Pour les marchés avec des connexions régulièrement mauvaises (zones rurales, transports, régions touchées par des problèmes de routage) :
- Définissez `fetchPolicy` sur `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` pour chaque récupération, sauf la toute première.
- Configurez un [paywall de secours](fallback-paywalls) pour chaque placement dans l'Adapty Dashboard.
- Définissez `loadTimeout` entre 3 et 5 secondes et acceptez le paywall de secours lorsque le timeout se déclenche.
- Ne conditionnez pas l'affichage du paywall à `getProfile`. Appelez `getPaywall` indépendamment pour qu'un profil lent ne bloque pas l'interface.
---
# File: android-test
---
---
title: "Tester et publier avec le SDK Android"
description: "Découvrez comment vérifier le statut d'abonnement dans votre application Android avec Adapty."
---
Si vous avez déjà intégré le SDK Adapty dans votre application Android, vous voudrez vérifier que tout est correctement configuré et que les achats fonctionnent comme prévu. Cela implique de tester à la fois l'intégration du SDK et le flux d'achat réel avec l'environnement sandbox de Google Play.
## Tester votre application \{#test-your-app\}
Pour tester vos achats intégrés de manière exhaustive, notamment les tests en sandbox et la validation des pistes fermées, consultez notre [guide de test](testing-on-android).
## Préparer la publication \{#prepare-for-release\}
Avant de soumettre votre application au store, suivez la [checklist de publication](release-checklist) pour confirmer que :
- La connexion au store et les notifications serveur sont configurées
- Les achats sont finalisés et remontés à Adapty
- L'accès est débloqué et restauré correctement
- Les exigences en matière de confidentialité et de révision sont respectées
---
# File: android-reference
---
---
title: "Référence pour le SDK Android"
description: "Documentation de référence pour le SDK Android Adapty."
---
Cette page contient la documentation de référence pour le SDK Android Adapty. Choisissez le sujet dont vous avez besoin :
- **[Modèles SDK](https://android.adapty.io)** - Modèles de données et structures utilisés par le SDK
- **[Gestion des erreurs](android-sdk-error-handling)** - Gestion des erreurs et résolution des problèmes
---
# File: android-sdk-error-handling
---
---
title: "Gérer les erreurs dans le SDK Android"
description: "Gérez efficacement les erreurs du SDK Android grâce au guide de dépannage d'Adapty."
---
Chaque erreur renvoyée par le SDK est de type `AdaptyError`.
:::tip
**Activez les journaux détaillés avant de déboguer.** La plupart des `AdaptyError` encapsulent une erreur sous-jacente de Play Billing, du réseau ou du backend. Avec les journaux détaillés activés (`Adapty.logLevel = AdaptyLogLevel.VERBOSE` — voir [Journalisation](sdk-installation-android#logging)), cette erreur encapsulée s'affiche dans la console, ce qui indique généralement la cause réelle.
:::
:::important
Si ces solutions ne résolvent pas votre problème, consultez [Autres problèmes](#other-issues) pour connaître les étapes à suivre avant de contacter le support afin de nous permettre de vous aider plus efficacement.
:::
| Erreur | Solution |
|----------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| UNKNOWN | Cette erreur indique qu'une erreur inconnue ou inattendue s'est produite. |
| [ITEM_UNAVAILABLE](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_UNAVAILABLE()) | Cette erreur survient principalement en phase de test. Elle peut signifier que les produits sont absents de la production ou que l'utilisateur n'appartient pas au groupe Testeurs dans Google Play. |
| ADAPTY_NOT_INITIALIZED | Le SDK Adapty n'est pas activé.
Ce cas se présente le plus souvent quand un écran de démarrage ou un hook d'interface précoce appelle des méthodes Adapty avant que `Adapty.activate` ait terminé. Le symptôme est intermittent et peut ne pas se reproduire sur un émulateur, car le timing diffère d'un appareil réel. Attendez que `Adapty.activate` soit terminé avant de planifier tout autre appel SDK. Consultez [l'ordre des appels dans le SDK Android](android-sdk-call-order) pour la séquence complète. Vous devez également [configurer le SDK Adapty](sdk-installation-android#activate-adapty-module-of-adapty-sdk) correctement à l'aide de la méthode `Adapty.activate`. |
| PROFILE_WAS_CHANGED | Le profil utilisateur a été modifié pendant l'opération.
Cela se produit lorsqu'une méthode est appelée alors qu'`Adapty.identify` est encore en cours — l'appel en vol atterrit sur un profil sur le point d'être remplacé, et le SDK le rejette. Attendez qu'`Adapty.identify` soit terminé avant de planifier d'autres appels SDK. Consultez [l'ordre des appels dans le SDK Android](android-sdk-call-order). |
| PRODUCT_NOT_FOUND | Cette erreur indique que le produit demandé à l'achat n'est pas disponible dans le store. |
| INVALID_JSON | Le JSON du paywall de secours local n'est pas valide.
Corrigez votre paywall anglais par défaut, puis remplacez les paywalls locaux invalides. Consultez la rubrique [Personnaliser le paywall avec Remote Config](customize-paywall-with-remote-config) pour savoir comment corriger un paywall, et [Définir les paywalls de secours locaux](fallback-paywalls) pour savoir comment remplacer les paywalls locaux.
|
| CURRENT_SUBSCRIPTION_TO_UPDATE
\_NOT_FOUND_IN_HISTORY
| L'abonnement d'origine à remplacer est introuvable dans les abonnements actifs. |
| [BILLING_SERVICE_TIMEOUT](https://developer.android.com/google/play/billing/errors#service_timeout_error_code_-3) | Cette erreur indique que la requête a atteint le délai d'attente maximal avant que Google Play puisse répondre. Cela peut être dû, par exemple, à un retard dans l'exécution de l'action demandée par l'appel à la Play Billing Library. |
| [FEATURE_NOT_SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED()) | La fonctionnalité demandée n'est pas prise en charge par le Play Store sur l'appareil actuel. |
| [BILLING_SERVICE_DISCONNECTED](https://developer.android.com/google/play/billing/errors#service_disconnected_error_code_-1) | Cette erreur indique que la connexion de l'application cliente au service Google Play Store via le `BillingClient` a été interrompue. |
| [BILLING_SERVICE_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#service_unavailable_error_code_2) | Cette erreur indique que le service Google Play Billing est actuellement indisponible. Dans la plupart des cas, cela signifie qu'il y a un problème de connexion réseau entre l'appareil client et les services Google Play Billing. |
| [BILLING_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Cette erreur indique qu'un problème de facturation s'est produit pendant le processus d'achat. Causes possibles :
1. L'application Play Store sur l'appareil de l'utilisateur est absente ou obsolète.
2. L'utilisateur se trouve dans un pays non pris en charge.
3. L'utilisateur fait partie d'un compte entreprise dont l'administrateur a désactivé les achats.
4. Google Play n'a pas pu débiter le moyen de paiement de l'utilisateur (par exemple, une carte de crédit expirée).
5. L'utilisateur n'est pas connecté à l'application Play Store.
|
| [DEVELOPER_ERROR](https://developer.android.com/google/play/billing/errors#developer_error) | Cette erreur indique que vous utilisez une API de manière incorrecte. |
| [BILLING_ERROR](https://developer.android.com/google/play/billing/errors#error_error_code_6) | Cette erreur indique un problème interne à Google Play lui-même. |
| [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED()) | Le produit a déjà été acheté. |
| [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED()) | Cette erreur indique que l'action demandée sur l'article a échoué car l'utilisateur n'en est pas propriétaire. |
| [BILLING_NETWORK_ERROR](https://developer.android.com/google/play/billing/errors#network_error_error_code_12) | Cette erreur indique qu'un problème de connexion réseau s'est produit entre l'appareil et les systèmes Play. |
| NO_PRODUCT_IDS_FOUND | Cette erreur indique qu'aucun des produits du paywall n'est disponible dans le store.
Si vous rencontrez cette erreur, suivez les étapes ci-dessous pour la résoudre :
- Vérifiez que tous les produits ont bien été ajoutés à l'Adapty Dashboard.
- Assurez-vous que le **Package name** de votre application correspond à celui indiqué dans la Google Play Console.
- Vérifiez que les identifiants de produits des stores correspondent à ceux que vous avez ajoutés au Dashboard. Notez que les identifiants ne doivent pas contenir le Bundle ID, sauf s'il est déjà inclus dans le store.
- Confirmez que le statut payant de l'application est **Active** dans vos paramètres fiscaux Google. Assurez-vous que vos informations fiscales sont à jour et que vos certificats sont valides.
- Vérifiez qu'un compte bancaire est associé à l'application afin qu'elle puisse être éligible à la monétisation.
- Vérifiez si les produits sont disponibles dans votre région.
- Assurez-vous que votre application figure dans l'un des canaux de test. Le canal **Internal testing** est l'option la plus simple, car il ne nécessite pas de validation et garde l'application invisible pour les clients.
|
| NO_PURCHASES_TO_RESTORE | Cette erreur indique que Google Play n'a trouvé aucun achat à restaurer. |
| AUTHENTICATION_ERROR | Vous devez [configurer le SDK Adapty](sdk-installation-android#activate-adapty-module-of-adapty-sdk) correctement à l'aide de la méthode `Adapty.activate`. |
| BAD_REQUEST | Requête incorrecte.
Assurez-vous d'avoir effectué toutes les étapes nécessaires à l'[intégration avec Google Play](google-play-store-connection-configuration). |
| SERVER_ERROR | Erreur serveur. |
| REQUEST_FAILED | Cette erreur indique un problème réseau qui ne peut pas être défini précisément. |
| DECODING_FAILED | Nous n'avons pas pu décoder la réponse.
Vérifiez votre code et assurez-vous que les paramètres que vous envoyez sont valides. Par exemple, cette erreur peut indiquer que vous utilisez une clé API invalide. |
| ANALYTICS_DISABLED | Nous ne pouvons pas traiter les événements d'analyse, car vous avez [désactivé cette option](analytics-integration#disabling-external-analytics-for-a-specific-customer). |
| WRONG_PARAMETER | Cette erreur indique que certains de vos paramètres sont incorrects : vide alors qu'il ne peut pas l'être, mauvais type, etc. |
## Autres problèmes \{#other-issues\}
Si vous n'avez pas encore trouvé de solution, voici les prochaines étapes possibles :
- **Mettre à jour le SDK vers la dernière version** : nous recommandons toujours de passer à la dernière version du SDK, car elle est plus stable et inclut des correctifs pour les problèmes connus.
- **Contacter l'équipe support ou obtenir de l'aide auprès d'autres développeurs** dans le [forum d'assistance](https://adapty.featurebase.app/).
- **Contacter l'équipe support via [support@adapty.io](mailto:support@adapty.io) ou via le chat** : si vous n'êtes pas prêt à mettre à jour le SDK ou si cela n'a pas résolu le problème, contactez notre équipe support. Notez que votre problème sera résolu plus rapidement si vous [activez la journalisation verbeuse](sdk-installation-android#logging) et partagez les logs avec l'équipe. Vous pouvez également joindre des extraits de code pertinents.
---
# File: android-sdk-migration-guides
---
---
title: "Guides de migration du SDK Android"
description: "Guides de migration pour les versions du SDK Android Adapty."
---
Cette page regroupe tous les guides de migration pour le SDK Android Adapty. Choisissez la version vers laquelle vous souhaitez migrer pour obtenir les instructions détaillées :
- **[Migrer vers la v4.0](migration-to-android-sdk-v4)**
- **[Migrer vers la v3.12](migration-to-android-312)**
- **[Migrer vers la v3.10](migration-to-android-310)**
- **[Migrer vers la v3.4](migration-to-android-sdk-34)**
- **[Migrer vers la v3.3](migration-to-android330)**
- **[Migrer vers la v3.0](migration-to-android-sdk-v3)**
---
# File: migration-to-android-sdk-v4
---
---
title: "Migrer le SDK Android Adapty vers la v. 4.0"
description: "Migrez vers le SDK Android Adapty v4.0 en remplaçant les API paywall par des API flow, compatibles avec le Flow Builder et le Paywall Builder."
---
Le SDK Android Adapty 4.0 introduit les flows et renomme les API paywall en conséquence. Les nouvelles API fonctionnent aussi bien avec le nouveau Flow Builder qu'avec le Paywall Builder existant — aucun changement de configuration n'est nécessaire côté Adapty Dashboard.
## Référence rapide \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` |
| `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` |
| `AdaptyUI.getViewConfiguration(paywall)` | `AdaptyUI.getFlowConfiguration(flow, locale)` |
| `AdaptyUI.LocalizedViewConfiguration` | `AdaptyUI.FlowConfiguration` |
| `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` |
| `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` |
| `AdaptyPaywall` | `AdaptyFlow` |
| `AdaptyUI.getPaywallView(...)` | `AdaptyUI.getFlowView(...)` |
| `AdaptyPaywallView` | `AdaptyFlowView` |
| `AdaptyPaywallScreen` (Compose) | `AdaptyFlowScreen` |
| `showPaywall(...)` | `showFlow(...)` |
| `AdaptyPaywallInsets` | `AdaptyFlowInsets` |
| `AdaptyUiEventListener` | `AdaptyFlowEventListener` |
| `AdaptyUiDefaultEventListener` | `AdaptyFlowDefaultEventListener` |
| `onPaywallShown` / `onPaywallClosed` | `onFlowShown` / `onFlowClosed` |
| `onRenderingError` | `onError` |
| `Adapty.updateAttribution(attribution, source)` (`source: String`) | `Adapty.updateAttribution(attribution, source)` (`source: AdaptyAttributionSource`) |
| `Adapty.setIntegrationIdentifier(key, value)` | `Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier)` |
`AdaptyPaywallProduct` garde son nom — les produits appartiennent toujours à un flow, et `getPaywallProducts` prend désormais un `AdaptyFlow`. Les autres méthodes de `AdaptyFlowEventListener` (`onProductSelected`, `onPurchaseStarted`, `onPurchaseFinished`, `onPurchaseFailure`, `onRestoreSuccess`, `onRestoreFailure`, `onActionPerformed`, `onAwaitingPurchaseParams`, `onLoadingProductsFailure`, etc.) conservent leurs noms et signatures.
## Installation \{#installation\}
Définissez la version `adapty-bom` sur `4.0.1` (ou ultérieure) et synchronisez le projet. Le BOM résout automatiquement les versions correspondantes de `android-sdk` et `android-ui`. Consultez [Installer le SDK Adapty](sdk-installation-android) pour les déclarations de dépendances.
## API supprimées et dépréciées \{#removed-and-deprecated-apis\}
- **`Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized, callback)`** — supprimée. Cette surcharge était dépréciée en v3. Passez les mêmes options via `AdaptyPurchaseParameters` à la place :
```diff showLineNumbers
- Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized) { result -> /* ... */ }
+ val params = AdaptyPurchaseParameters.Builder()
+ .withSubscriptionUpdateParams(subscriptionUpdateParams)
+ .withOfferPersonalized(isOfferPersonalized)
+ .build()
+ Adapty.makePurchase(activity, product, params) { result -> /* ... */ }
```
- **Les onboardings sont obsolètes.** `AdaptyUI.getOnboardingView` et `AdaptyUI.getOnboardingConfiguration` sont marqués `@Deprecated` dans la version 4.0 — migrez vos onboardings vers des flows créés dans le [Flow Builder](adapty-flow-builder).
## Récupération des flows \{#fetching-flows\}
### getPaywall + getViewConfiguration → getFlow + getFlowConfiguration
Le type de retour de la récupération passe de `AdaptyPaywall` à `AdaptyFlow`, et le chargeur de configuration est renommé de `AdaptyUI.getViewConfiguration` en `AdaptyUI.getFlowConfiguration` (retournant `AdaptyUI.FlowConfiguration` au lieu de `AdaptyUI.LocalizedViewConfiguration`). Le paramètre `locale` sort de l'appel de récupération et passe dans `getFlowConfiguration` :
```diff showLineNumbers
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result ->
+ Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
if (result is AdaptyResult.Success) {
- val paywall = result.value
- if (!paywall.hasViewConfiguration) return@getPaywall
- AdaptyUI.getViewConfiguration(paywall) { configResult ->
+ val flow = result.value
+ if (!flow.hasViewConfiguration) return@getFlow
+ AdaptyUI.getFlowConfiguration(flow, locale = "en") { configResult ->
if (configResult is AdaptyResult.Success) {
val flowConfiguration = configResult.value
}
}
}
}
```
`locale` reste optionnel dans `getFlowConfiguration` : omettez-le et la vue s'affiche en `en`, ou dans la langue par défaut du flow si celui-ci ne dispose pas de `en`. Voir [Localisations et codes de langue](android-localizations-and-locale-codes).
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` prend désormais un `AdaptyFlow` retourné par `Adapty.getFlow` :
```diff showLineNumbers
- Adapty.getPaywallProducts(paywall) { result -> /* products */ }
+ Adapty.getPaywallProducts(flow) { result -> /* products */ }
```
### Fichiers de secours \{#fallback-files\}
Le format du fichier de secours [a changé avec le SDK v4](fallback-flows). Téléchargez le nouveau fichier depuis **[Placements](https://app.adapty.io/placements)** > **Fallbacks** et intégrez-le dans votre application.
## Suivi des vues de flow \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` est renommé `logShowFlow` et prend désormais un `AdaptyFlow` à la place d'un `AdaptyPaywall`. L'événement est toujours enregistré pour la même variation, donc les métriques de funnel et de test A/B existantes continuent de fonctionner sans modification du tableau de bord.
```diff showLineNumbers
- Adapty.logShowPaywall(paywall)
+ Adapty.logShowFlow(flow)
```
Comme dans la v3, vous n'avez pas besoin d'appeler cette méthode pour afficher des flows ou des paywalls générés par le [Flow Builder](adapty-flow-builder) ou le [Paywall Builder](adapty-paywall-builder) — Adapty suit ces vues automatiquement.
## Afficher des flows \{#displaying-flows\}
### getPaywallView / AdaptyPaywallView → getFlowView / AdaptyFlowView
Renommez la méthode factory et le type de vue, et transmettez la `AdaptyUI.FlowConfiguration` :
```diff showLineNumbers
- val paywallView = AdaptyUI.getPaywallView(
- activity,
- viewConfiguration,
- products,
- eventListener,
- )
+ val flowView = AdaptyUI.getFlowView(
+ activity,
+ flowConfiguration,
+ products,
+ eventListener,
+ )
```
Si vous créez la vue directement, la méthode show est également renommée :
```diff showLineNumbers
- val paywallView = AdaptyPaywallView(activity)
- paywallView.showPaywall(viewConfiguration, products, eventListener)
+ val flowView = AdaptyFlowView(activity)
+ flowView.showFlow(flowConfiguration, products, eventListener)
```
Dans les layouts XML, mettez à jour le tag de la vue :
```diff showLineNumbers
-
+
```
Le paramètre optionnel `personalizedOfferResolver` a été supprimé de `getFlowView` / `showFlow` / `AdaptyFlowScreen`. Pour indiquer un prix personnalisé, définissez-le par produit via `onAwaitingPurchaseParams` (`AdaptyPurchaseParameters.Builder().withOfferPersonalized(true)`). Un nouveau paramètre optionnel `customAssets` vous permet de remplacer des images et des vidéos à l'exécution — voir [Personnaliser les assets](android-get-pb-paywalls#customize-assets).
### AdaptyPaywallScreen → AdaptyFlowScreen
Dans Jetpack Compose, renommez le composable et mettez à jour le paramètre de configuration :
```diff showLineNumbers
- AdaptyPaywallScreen(
- viewConfiguration,
+ AdaptyFlowScreen(
+ flowConfiguration,
products,
eventListener,
)
```
## Gestion des événements \{#handling-events\}
L'écouteur d'événements est renommé de `AdaptyUiEventListener` en `AdaptyFlowEventListener` (et `AdaptyUiDefaultEventListener` en `AdaptyFlowDefaultEventListener`). La plupart des noms de méthodes restent inchangés ; les callbacks de cycle de vie et de rendu sont renommés :
```diff showLineNumbers
- class YourListener : AdaptyUiDefaultEventListener() {
+ class YourListener : AdaptyFlowDefaultEventListener() {
- override fun onPaywallShown(context: Context) {}
- override fun onPaywallClosed() {}
+ override fun onFlowShown(context: Context) {}
+ override fun onFlowClosed() {}
- override fun onRenderingError(error: AdaptyError, context: Context) {}
+ override fun onError(error: AdaptyError, context: Context) {}
}
```
Les corps des gestionnaires existants ne nécessitent pas de modifications du code — il suffit de renommer le type et les surcharges. `onError` se déclenche pour les mêmes erreurs de rendu que `onRenderingError`, plus d'autres erreurs d'exécution non liées aux achats. Consultez [Gérer les événements de flow et de paywall](android-handling-events) pour la liste complète des callbacks.
v4 ajoute également un callback `onBackPressed(context): Boolean`, et son comportement par défaut change la façon dont le bouton Retour du système fonctionne. Auparavant, le bouton Retour (ou le geste de retour) était transmis à votre activité ou fragment, ce qui fermait généralement le paywall. Dans v4, l'implémentation par défaut consomme l'appui, donc **le bouton Retour du système ne ferme plus un flow tout seul** — ce qui correspond au comportement iOS, où un flow ne peut pas être fermé par un geste système. Donnez aux utilisateurs un moyen explicite de quitter (un bouton **Close** ou une action `on_device_back`), ou surchargez `onBackPressed` pour retourner `false` afin de restaurer l'ancien comportement. Consultez [Bouton Retour du système](android-handling-events#system-back-button) pour plus de détails.
Le gestionnaire d'achat par défaut ne ferme plus non plus l'écran. Dans la v3, le `onPurchaseFinished` par défaut fermait le paywall après tout achat terminé qui n'était pas une annulation de l'utilisateur (achat réussi ou en attente). Dans la v4, c'est un no-op, donc **un flow reste ouvert après un achat jusqu'à ce que vous le fermiez vous-même** — ce qui correspond au comportement iOS. Si vous comptiez sur cette fermeture automatique, fermez l'écran vous-même une fois l'achat terminé. Consultez [Achat réussi, annulé ou en attente](android-handling-events#successful-canceled-or-pending-purchase) pour un exemple.
## Identifiants d'attribution et d'intégration \{#attribution-and-integration-identifiers\}
### updateAttribution
Le paramètre `source` passe de `String` au nouveau type `AdaptyAttributionSource`, et `attribution` est désormais un `Map` (une surcharge `String` JSON est également disponible). Utilisez l'une des sources prédéfinies :
```diff showLineNumbers
- Adapty.updateAttribution(attribution, "appsflyer") { error -> /* handle the error */ }
+ Adapty.updateAttribution(attribution, AdaptyAttributionSource.APPSFLYER) { error -> /* handle the error */ }
```
Sources prédéfinies : `AdaptyAttributionSource.APPLE_ADS`, `.ADJUST`, `.APPSFLYER`, `.BRANCH`, `.TENJIN`. Pour toute autre source, créez-en une à partir d'une chaîne : `AdaptyAttributionSource("your_source")`.
### setIntegrationIdentifier
`setIntegrationIdentifier(key, value)` est remplacé par une méthode qui accepte une ou plusieurs valeurs `AdaptyIntegrationIdentifier`. Construisez chaque identifiant avec une méthode utilitaire plutôt que de passer une clé brute en chaîne de caractères :
```diff showLineNumbers
- Adapty.setIntegrationIdentifier("appsflyer_id", appsFlyerId) { error -> /* handle the error */ }
+ Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId)) { error -> /* handle the error */ }
```
Vous pouvez définir plusieurs identifiants en un seul appel :
```kotlin showLineNumbers
Adapty.setIntegrationIdentifier(
listOf(
AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId),
AdaptyIntegrationIdentifier.adjustDeviceId(adjustDeviceId),
)
) { error -> /* handle the error */ }
```
Remplacez chaque ancienne chaîne de clé par sa méthode pratique correspondante :
| Clé v3 | Méthode `AdaptyIntegrationIdentifier` v4 |
|---|---|
| `"adjust_device_id"` | `adjustDeviceId(value)` |
| `"airbridge_device_id"` | `airbridgeDeviceId(value)` |
| `"amplitude_user_id"` | `amplitudeUserId(value)` |
| `"amplitude_device_id"` | `amplitudeDeviceId(value)` |
| `"appmetrica_device_id"` | `appmetricaDeviceId(value)` |
| `"appmetrica_profile_id"` | `appmetricaProfileId(value)` |
| `"appsflyer_id"` | `appsflyerId(value)` |
| `"branch_id"` | `branchId(value)` |
| `"facebook_anonymous_id"` | `facebookAnonymousId(value)` |
| `"firebase_app_instance_id"` | `firebaseAppInstanceId(value)` |
| `"mixpanel_user_id"` | `mixpanelUserId(value)` |
| `"one_signal_subscription_id"` | `oneSignalSubscriptionId(value)` |
| `"one_signal_player_id"` | `oneSignalPlayerId(value)` |
| `"posthog_distinct_user_id"` | `posthogDistinctUserId(value)` |
| `"pushwoosh_hwid"` | `pushwooshHWID(value)` |
| `"tenjin_analytics_installation_id"` | `tenjinAnalyticsInstallationId(value)` |
Pour une clé qui ne figure pas dans cette liste, construisez l'identifiant directement à partir d'une `Key` personnalisée : `AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key("custom"), customValue)`.
---
# File: migration-to-android-312
---
---
title: "Migrer le SDK Android Adapty vers la v3.12"
description: "Migrez vers le SDK Android Adapty v3.12 pour de meilleures performances et de nouvelles fonctionnalités de monétisation."
---
Dans le SDK Adapty 3.12.0, nous avons supprimé la méthode `logShowOnboarding` du SDK.
Si vous utilisiez cette méthode, elle ne sera plus disponible lorsque vous mettrez à jour le SDK vers la version 3.12 ou ultérieure.
À la place, vous pouvez [créer des onboardings dans le générateur d'onboarding no-code d'Adapty](onboardings). Les analyses de ces onboardings sont suivies automatiquement, et vous disposez de nombreuses options de personnalisation.
---
# File: migration-to-android-310
---
---
title: "Guide de migration vers Android Adapty SDK 3.10.0"
description: ""
---
Adapty SDK 3.10.0 est une version majeure qui apporte des améliorations nécessitant toutefois quelques étapes de migration de votre part :
1. `AdaptyUiPersonalizedOfferResolver` a été supprimé. Si vous l'utilisiez, passez-le dans le callback `onAwaitingPurchaseParams`.
2. Mettez à jour la signature de la méthode `onAwaitingSubscriptionUpdateParams` pour les paywalls du Paywall Builder.
## Mettre à jour le callback des paramètres d'achat \{#update-purchase-parameters-callback\}
La méthode `onAwaitingSubscriptionUpdateParams` a été renommée en `onAwaitingPurchaseParams` et utilise désormais `AdaptyPurchaseParameters` à la place de `AdaptySubscriptionUpdateParameters`. Cela vous permet de spécifier des paramètres de remplacement d'abonnement (crossgrade) et d'indiquer si le prix est personnalisé ([en savoir plus](https://developer.android.com/google/play/billing/integrate#personalized-price)), ainsi que d'autres paramètres d'achat.
```diff showLineNumbers
- override fun onAwaitingSubscriptionUpdateParams(
- product: AdaptyPaywallProduct,
- context: Context,
- onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback,
- ) {
- onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...))
- }
+ override fun onAwaitingPurchaseParams(
+ product: AdaptyPaywallProduct,
+ context: Context,
+ onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback,
+ ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked {
+ onPurchaseParamsReceived(
+ AdaptyPurchaseParameters.Builder()
+ .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...))
+ .withOfferPersonalized(true)
+ .build()
+ )
+ return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked
+ }
```
Si aucun paramètre supplémentaire n'est nécessaire, vous pouvez simplement utiliser :
```kotlin showLineNumbers
+ override fun onAwaitingPurchaseParams(
product: AdaptyPaywallProduct,
context: Context,
onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback,
): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked {
onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty)
return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked
}
```
---
# File: migration-to-android-sdk-34
---
---
title: "Migrer le SDK Adapty Android vers v3.4"
description: "Migrez vers le SDK Adapty Android v3.4 pour de meilleures performances et de nouvelles fonctionnalités de monétisation."
---
Le SDK Adapty 3.4.0 est une version majeure qui introduit des améliorations nécessitant des étapes de migration de votre côté.
## Mettre à jour les fichiers de paywall de secours \{#update-fallback-paywall-files\}
Mettez à jour vos fichiers de paywall de secours pour assurer la compatibilité avec la nouvelle version du SDK :
1. [Téléchargez les fichiers de paywall de secours mis à jour](fallback-paywalls) depuis l'Adapty Dashboard.
2. [Remplacez les paywalls de secours existants dans votre application mobile](android-use-fallback-paywalls) par les nouveaux fichiers.
## Mettre à jour l'implémentation du mode Observateur \{#update-implementation-of-observer-mode\}
Si vous utilisez le mode Observateur, assurez-vous de mettre à jour son implémentation.
Dans les versions précédentes, vous deviez restaurer les achats pour qu'Adapty puisse reconnaître les transactions effectuées via votre propre infrastructure, car Adapty n'y avait pas accès directement en mode Observateur. Si vous utilisiez des paywalls, vous deviez également associer manuellement chaque transaction au paywall qui l'avait initiée.
Dans la nouvelle version, vous devez signaler explicitement chaque transaction pour qu'Adapty puisse la reconnaître. Si vous utilisez des paywalls, vous devez également transmettre l'ID de variation pour lier la transaction au paywall utilisé.
:::warning
**Ne sautez pas le signalement des transactions !**
Si vous n'appelez pas `reportTransaction`, Adapty ne reconnaîtra pas la transaction, elle n'apparaîtra pas dans les analyses et ne sera pas envoyée aux intégrations.
:::
```diff showLineNumbers
- Adapty.restorePurchases { result ->
- if (result is AdaptyResult.Success) {
- // success
- }
- }
-
- Adapty.setVariationId(transactionId, variationId) { error ->
- if (error == null) {
- // success
- }
- }
+ val transactionInfo = TransactionInfo.fromPurchase(purchase)
+
+ Adapty.reportTransaction(transactionInfo, variationId) { result ->
+ if (result is AdaptyResult.Success) {
+ // success
+ }
+ }
```
```diff showLineNumbers
- Adapty.restorePurchases(result -> {
- if (result instanceof AdaptyResult.Success) {
- // success
- }
- });
-
- Adapty.setVariationId(transactionId, variationId, error -> {
- if (error == null) {
- // success
- }
- });
+ TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase);
+
+ Adapty.reportTransaction(transactionInfo, variationId, result -> {
+ if (result instanceof AdaptyResult.Success) {
+ // success
+ }
+ });
```
---
# File: migration-to-android330
---
---
title: "Migrer le SDK Adapty Android vers v3.3"
description: "Migrez vers le SDK Adapty Android v3.3 pour de meilleures performances et de nouvelles fonctionnalités de monétisation."
---
Le SDK Adapty 3.3.0 est une version majeure qui apporte des améliorations pouvant nécessiter quelques étapes de migration de votre part.
1. Mettez à jour la façon dont vous gérez les achats dans les paywalls non créés avec le Paywall Builder. Arrêtez de traiter les codes d'erreur `USER_CANCELED` et `PENDING_PURCHASE`. Un achat annulé n'est plus considéré comme une erreur et apparaîtra désormais dans les résultats d'achat sans erreur.
2. Remplacez les événements `onPurchaseCanceled` et `onPurchaseSuccess` par le nouvel événement `onPurchaseFinished` pour les paywalls créés avec le Paywall Builder. Ce changement est dû à la même raison : les achats annulés ne sont plus traités comme des erreurs et seront inclus dans les résultats d'achat sans erreur.
3. Modifiez la signature de la méthode `onAwaitingSubscriptionUpdateParams` pour les paywalls Paywall Builder.
4. Mettez à jour la méthode utilisée pour fournir les paywalls de secours si vous passez l'URI du fichier directement.
5. Mettez à jour les configurations d'intégration pour Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase et Google Analytics, Mixpanel, OneSignal, Pushwoosh.
## Mettre à jour les achats \{#update-making-purchase\}
Auparavant, les achats annulés et en attente étaient considérés comme des erreurs et retournaient respectivement les codes `USER_CANCELED` et `PENDING_PURCHASE`.
Désormais, une nouvelle classe `AdaptyPurchaseResult` est utilisée pour indiquer les achats annulés, réussis et en attente. Mettez à jour le code d'achat de la façon suivante :
~~~diff
Adapty.makePurchase(activity, product) { result ->
when (result) {
is AdaptyResult.Success -> {
- val info = result.value
- val profile = info?.profile
-
- if (profile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true) {
- // Grant access to the paid features
- }
+ when (val purchaseResult = result.value) {
+ is AdaptyPurchaseResult.Success -> {
+ val profile = purchaseResult.profile
+ if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
+ // Grant access to the paid features
+ }
+ }
+
+ is AdaptyPurchaseResult.UserCanceled -> {
+ // Handle the case where the user canceled the purchase
+ }
+
+ is AdaptyPurchaseResult.Pending -> {
+ // Handle deferred purchases (e.g., the user will pay offline with cash
+ }
+ }
}
is AdaptyResult.Error -> {
val error = result.error
// Handle the error
}
}
}
~~~
Pour un exemple de code complet, consultez la page [Effectuer des achats dans l'application mobile](android-making-purchases#make-purchase).
## Modifier les événements d'achat du Paywall Builder \{#modify-paywall-builder-purchase-events\}
1. Ajoutez l'événement `onPurchaseFinished` :
```diff showLineNumbers
+ public override fun onPurchaseFinished(
+ purchaseResult: AdaptyPurchaseResult,
+ product: AdaptyPaywallProduct,
+ context: Context,
+ ) {
+ when (purchaseResult) {
+ is AdaptyPurchaseResult.Success -> {
+ // Grant access to the paid features
+ }
+ is AdaptyPurchaseResult.UserCanceled -> {
+ // Handle the case where the user canceled the purchase
+ }
+ is AdaptyPurchaseResult.Pending -> {
+ // Handle deferred purchases (e.g., the user will pay offline with cash)
+ }
+ }
+ }
```
Pour un exemple de code complet, consultez [Achat réussi, annulé ou en attente](android-handling-events#successful-canceled-or-pending-purchase) et la description de l'événement.
2. Supprimez le traitement de l'événement `onPurchaseCancelled` :
```diff showLineNumbers
- public override fun onPurchaseCanceled(
- product: AdaptyPaywallProduct,
- context: Context,
- ) {}
```
3. Supprimez `onPurchaseSuccess` :
```diff showLineNumbers
- public override fun onPurchaseSuccess(
- profile: AdaptyProfile?,
- product: AdaptyPaywallProduct,
- context: Context,
- ) {
- // Your logic on successful purchase
- }
```
## Modifier la signature de la méthode onAwaitingSubscriptionUpdateParams \{#change-the-signature-of--onawaitingsubscriptionupdateparams-method\}
Désormais, si un nouvel abonnement est souscrit alors qu'un autre est encore actif, appelez `onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters...))` si le nouvel abonnement doit remplacer l'abonnement actif, ou `onSubscriptionUpdateParamsReceived(null)` si l'abonnement actif doit rester actif et le nouveau être ajouté séparément :
```diff showLineNumbers
- public override fun onAwaitingSubscriptionUpdateParams(
- product: AdaptyPaywallProduct,
- context: Context,
- ): AdaptySubscriptionUpdateParameters? {
- return AdaptySubscriptionUpdateParameters(...)
- }
+ public override fun onAwaitingSubscriptionUpdateParams(
+ product: AdaptyPaywallProduct,
+ context: Context,
+ onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback,
+ ) {
+ onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...))
+ }
```
Consultez la section [Mettre à niveau un abonnement](android-handling-events#upgrade-subscription) pour l'exemple de code final.
## Mettre à jour la fourniture des paywalls de secours \{#update-providing-fallback-paywalls\}
Si vous passez l'URI d'un fichier pour fournir des paywalls de secours, mettez à jour votre code de la façon suivante :
```diff showLineNumbers
val fileUri: Uri = // Get the URI for the file with fallback paywalls
- Adapty.setFallbackPaywalls(fileUri, callback)
+ Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback)
```
```diff showLineNumbers
Uri fileUri = // Get the URI for the file with fallback paywalls
- Adapty.setFallbackPaywalls(fileUri, callback);
+ Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback);
```
## Mettre à jour la configuration du SDK des intégrations tierces \{#update-third-party-integration-sdk-configuration\}
Pour garantir le bon fonctionnement des intégrations avec le SDK Adapty Android 3.3.0 et versions ultérieures, mettez à jour vos configurations SDK pour les intégrations suivantes comme décrit dans les sections ci-dessous.
### Adjust \{#adjust\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Adjust](adjust#connect-your-app-to-adjust).
```diff showLineNumbers
- Adjust.getAttribution { attribution ->
- if (attribution == null) return@getAttribution
-
- Adjust.getAdid { adid ->
- if (adid == null) return@getAdid
-
- Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST, adid) { error ->
- // Handle the error
- }
- }
- }
+ Adjust.getAdid { adid ->
+ if (adid == null) return@getAdid
+
+ Adapty.setIntegrationIdentifier("adjust_device_id", adid) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
+ }
+
+ Adjust.getAttribution { attribution ->
+ if (attribution == null) return@getAttribution
+
+ Adapty.updateAttribution(attribution, "adjust") { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
+ }
```
```diff showLineNumbers
val config = AdjustConfig(context, adjustAppToken, environment)
config.setOnAttributionChangedListener { attribution ->
attribution?.let { attribution ->
- Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST) { error ->
+ Adapty.updateAttribution(attribution, "adjust") { error ->
if (error != null) {
// Handle the error
}
}
}
}
Adjust.onCreate(config)
```
### AirBridge \{#airbridge\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AirBridge](airbridge#connect-your-app-to-airbridge).
```diff showLineNumbers
Airbridge.getDeviceInfo().getUUID(object: AirbridgeCallback.SimpleCallback() {
override fun onSuccess(result: String) {
- val params = AdaptyProfileParameters.Builder()
- .withAirbridgeDeviceId(result)
- .build()
- Adapty.updateProfile(params) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier("airbridge_device_id", result) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
}
override fun onFailure(throwable: Throwable) {
}
})
```
### Amplitude \{#amplitude\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Amplitude](amplitude#sdk-configuration).
```diff showLineNumbers
// For Amplitude maintenance SDK (obsolete)
val amplitude = Amplitude.getInstance()
val amplitudeDeviceId = amplitude.getDeviceId()
val amplitudeUserId = amplitude.getUserId()
//for actual Amplitude Kotlin SDK
val amplitude = Amplitude(
Configuration(
apiKey = AMPLITUDE_API_KEY,
context = applicationContext
)
)
val amplitudeDeviceId = amplitude.store.deviceId
val amplitudeUserId = amplitude.store.userId
//
- val params = AdaptyProfileParameters.Builder()
- .withAmplitudeDeviceId(amplitudeDeviceId)
- .withAmplitudeUserId(amplitudeUserId)
- .build()
- Adapty.updateProfile(params) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier("amplitude_user_id", amplitudeUserId) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
+ Adapty.setIntegrationIdentifier("amplitude_device_id", amplitudeDeviceId) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
```
### AppMetrica \{#appmetrica\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AppMetrica](appmetrica#sdk-configuration).
```diff showLineNumbers
val startupParamsCallback = object: StartupParamsCallback {
override fun onReceive(result: StartupParamsCallback.Result?) {
val deviceId = result?.deviceId ?: return
- val params = AdaptyProfileParameters.Builder()
- .withAppmetricaDeviceId(deviceId)
- .withAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID")
- .build()
- Adapty.updateProfile(params) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
+
+ Adapty.setIntegrationIdentifier("appmetrica_profile_id", "YOUR_ADAPTY_CUSTOMER_USER_ID") { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
}
override fun onRequestError(
reason: StartupParamsCallback.Reason,
result: StartupParamsCallback.Result?
) {
// Handle the error
}
}
AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID))
```
### AppsFlyer \{#appsflyer\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration AppsFlyer](appsflyer#connect-your-app-to-appsflyer).
```diff showLineNumbers
val conversionListener: AppsFlyerConversionListener = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(conversionData: Map) {
- Adapty.updateAttribution(
- conversionData,
- AdaptyAttributionSource.APPSFLYER,
- AppsFlyerLib.getInstance().getAppsFlyerUID(context)
- ) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(context)
+ Adapty.setIntegrationIdentifier("appsflyer_id", uid) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
+ Adapty.updateAttribution(conversionData, "appsflyer") { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
}
}
```
### Branch \{#branch\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Branch](branch#connect-your-app-to-branch).
```diff showLineNumbers
// Login and update attribution
Branch.getAutoInstance(this)
.setIdentity("YOUR_USER_ID") { referringParams, error ->
referringParams?.let { data ->
- Adapty.updateAttribution(data, AdaptyAttributionSource.BRANCH) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.updateAttribution(data, "branch") { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
}
}
// Logout
Branch.getAutoInstance(context).logout()
```
### Facebook Ads \{#facebook-ads\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads).
```diff showLineNumbers
- val builder = AdaptyProfileParameters.Builder()
- .withFacebookAnonymousId(AppEventsLogger.getAnonymousAppDeviceGUID(context))
-
- Adapty.updateProfile(builder.build()) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier(
+ "facebook_anonymous_id",
+ AppEventsLogger.getAnonymousAppDeviceGUID(context)
+ ) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
```
### Firebase et Google Analytics \{#firebase-and-google-analytics\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Firebase et Google Analytics](firebase-and-google-analytics).
```diff showLineNumbers
// After Adapty.activate()
FirebaseAnalytics.getInstance(context).appInstanceId.addOnSuccessListener { appInstanceId ->
- Adapty.updateProfile(
- AdaptyProfileParameters.Builder()
- .withFirebaseAppInstanceId(appInstanceId)
- .build()
- ) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
}
```
```diff showLineNumbers
// After Adapty.activate()
- FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> {
- AdaptyProfileParameters params = new AdaptyProfileParameters.Builder()
- .withFirebaseAppInstanceId(appInstanceId)
- .build();
-
- Adapty.updateProfile(params, error -> {
- if (error != null) {
- // Handle the error
- }
- });
- });
+ FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> {
+ Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId, error -> {
+ if (error != null) {
+ // Handle the error
+ }
+ });
+ });
```
### Mixpanel \{#mixpanel\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Mixpanel](mixpanel#sdk-configuration).
```diff showLineNumbers
- val params = AdaptyProfileParameters.Builder()
- .withMixpanelUserId(mixpanelAPI.distinctId)
- .build()
-
- Adapty.updateProfile(params) { error ->
- if (error != null) {
- // Handle the error
- }
- }
+ Adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelAPI.distinctId) { error ->
+ if (error != null) {
+ // Handle the error
+ }
+ }
```
### OneSignal \{#onesignal\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration OneSignal](onesignal#sdk-configuration).
```diff showLineNumbers
// SubscriptionID
val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver {
override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) {
- val params = AdaptyProfileParameters.Builder()
- .withOneSignalSubscriptionId(state.current.id)
- .build()
-
- Adapty.updateProfile(params) { error ->
+ Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.current.id) { error ->
if (error != null) {
// Handle the error
}
}
}
}
```
```diff showLineNumbers
// SubscriptionID
IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> {
- AdaptyProfileParameters params = new AdaptyProfileParameters.Builder()
- .withOneSignalSubscriptionId(state.getCurrent().getId())
- .build();
- Adapty.updateProfile(params, error -> {
+ Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.getCurrent().getId(), error -> {
if (error != null) {
// Handle the error
}
});
};
```
```diff showLineNumbers
// PlayerID
val osSubscriptionObserver = OSSubscriptionObserver { stateChanges ->
stateChanges?.to?.userId?.let { playerId ->
- val params = AdaptyProfileParameters.Builder()
- .withOneSignalPlayerId(playerId)
- .build()
-
- Adapty.updateProfile(params) { error ->
+ Adapty.setIntegrationIdentifier("one_signal_player_id", playerId) { error ->
if (error != null) {
// Handle the error
}
- }
}
}
```
```diff showLineNumbers
// PlayerID
OSSubscriptionObserver osSubscriptionObserver = stateChanges -> {
OSSubscriptionState to = stateChanges != null ? stateChanges.getTo() : null;
String playerId = to != null ? to.getUserId() : null;
if (playerId != null) {
- AdaptyProfileParameters params1 = new AdaptyProfileParameters.Builder()
- .withOneSignalPlayerId(playerId)
- .build();
-
- Adapty.updateProfile(params1, error -> {
+ Adapty.setIntegrationIdentifier("one_signal_player_id", playerId, error -> {
if (error != null) {
// Handle the error
}
- });
}
};
```
### Pushwoosh \{#pushwoosh\}
Mettez à jour le code de votre application mobile comme indiqué ci-dessous. Pour un exemple de code complet, consultez la [Configuration du SDK pour l'intégration Pushwoosh](pushwoosh#sdk-configuration).
```diff showLineNumbers
- val params = AdaptyProfileParameters.Builder()
- .withPushwooshHwid(Pushwoosh.getInstance().hwid)
- .build()
- Adapty.updateProfile(params) { error ->
+ Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().hwid) { error ->
if (error != null) {
// Handle the error
}
}
```
```diff showLineNumbers
- AdaptyProfileParameters params = new AdaptyProfileParameters.Builder()
- .withPushwooshHwid(Pushwoosh.getInstance().getHwid())
- .build();
-
- Adapty.updateProfile(params, error -> {
+ Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().getHwid(), error -> {
if (error != null) {
// Handle the error
}
});
```
---
# File: migration-to-android-sdk-v3
---
---
title: "Migrer le SDK Adapty Android vers la v3.0"
description: "Migrez vers le SDK Adapty Android v3.0 pour de meilleures performances et de nouvelles fonctionnalités de monétisation."
---
Le SDK Adapty v3.0 apporte la prise en charge du nouveau [Adapty Paywall Builder](adapty-paywall-builder), la nouvelle version de l'outil no-code convivial pour créer des paywalls. Grâce à sa flexibilité maximale et ses riches capacités de design, vos paywalls deviendront plus efficaces et rentables.
Les SDK Adapty sont distribués sous forme de BoM (Bill of Materials), ce qui garantit la cohérence des versions du SDK Adapty et du SDK AdaptyUI dans votre application.
Pour migrer vers la v3.0, mettez à jour votre code comme suit :
```diff showLineNumbers
dependencies {
...
- implementation 'io.adapty:android-sdk:2.11.5'
- implementation 'io.adapty:android-ui:2.11.3'
+ implementation platform('io.adapty:adapty-bom:3.0.4')
+ implementation 'io.adapty:android-sdk'
+ implementation 'io.adapty:android-ui'
}
```
```diff showLineNumbers
dependencies {
...
- implementation("io.adapty:android-sdk:2.11.5")
- implementation("io.adapty:android-ui:2.11.3")
+ implementation(platform("io.adapty:adapty-bom:3.0.4"))
+ implementation("io.adapty:android-sdk")
+ implementation("io.adapty:android-ui")
}
```
```diff showLineNumbers
//libs.versions.toml
[versions]
..
- adapty = "2.11.5"
- adaptyUi = "2.11.3"
+ adaptyBom = "3.0.4"
[libraries]
..
- adapty = { group = "io.adapty", name = "android-sdk", version.ref = "adapty" }
- adapty-ui = { group = "io.adapty", name = "android-ui", version.ref = "adaptyUi" }
+ adapty-bom = { module = "io.adapty:adapty-bom", version.ref = "adaptyBom" }
+ adapty = { module = "io.adapty:android-sdk" }
+ adapty-ui = { module = "io.adapty:android-ui" }
//module-level build.gradle.kts
dependencies {
...
+ implementation(libs.adapty.bom)
implementation(libs.adapty)
implementation(libs.adapty.ui)
}
```
---
# End of Documentation
_Generated on: 2026-08-04T15:08:25.903Z_
_Successfully processed: 49/49 files_