---
title: "Afficher les flows et paywalls - Android"
description: "Présentez des flows et des paywalls aux utilisateurs dans votre application Android."
---

<MethodPromo method="getFlow" label="Display flows and paywalls" />

Si vous avez créé un flow ou un paywall, vous n'avez pas à vous soucier de son rendu dans le code de votre application mobile pour l'afficher à l'utilisateur. Un tel flow ou paywall contient à la fois ce qui doit être affiché et 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).

<Tabs groupId="current-os" queryString>
<TabItem value="views" label="Views" default>

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

<Tabs groupId="current-os" queryString>
  <TabItem value="kotlin" label="Kotlin (option 1)" default>

```kotlin showLineNumbers
   val flowView = AdaptyUI.getFlowView(
       activity,
       flowConfiguration,
       products,
       eventListener,
       insets,
       customAssets,
       tagResolver,
       timerResolver,
   )
```
</TabItem>
<TabItem value="kotlin2" label="Kotlin (option 2)" default>

```kotlin showLineNumbers
   val flowView =
        AdaptyFlowView(activity) // or retrieve it from xml
   ...
   with(flowView) {
       showFlow(
           flowConfiguration,
           products,
					 eventListener,
           insets,
           customAssets,
           tagResolver,
           timerResolver,
       )
   }
```

</TabItem>
<TabItem value="java" label="Java (option 1)" default>

```java showLineNumbers
AdaptyFlowView flowView = AdaptyUI.getFlowView(
        activity,
        flowConfiguration,
        products,
        eventListener,
        insets,
        customAssets,
        tagResolver,
        timerResolver
);
```
</TabItem>
<TabItem value="java2" label="Java (option 2)" default>

```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);
```

</TabItem>
<TabItem value="XML" label="XML" default>

```xml showLineNumbers
<com.adapty.ui.AdaptyFlowView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```
</TabItem>
</Tabs>

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()`.

</TabItem>
<TabItem value="compose" label="Jetpack Compose" default>

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,
)
```
</TabItem>
</Tabs>

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 | <p>Les insets sont les espaces autour du flow qui empêchent les éléments cliquables d'être masqués par les barres système.</p><p>Par défaut : `Unspecified`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les flows plein écran. </p><p>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.</p> |
| **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 :

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>
```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,
       )
}
```
</TabItem>
<TabItem value="java" label="Java" default>
```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;
});
```
</TabItem>
</Tabs>

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

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```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 */ } )
}
```

</TabItem>
<TabItem value="java" label="Java" default>

```java showLineNumbers

...

Map<String, Date> 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 */
    }
};
```

</TabItem>

</Tabs>

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 :

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```kotlin showLineNumbers
val customTags = mapOf("USERNAME" to "John")
val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] }
```

</TabItem>
<TabItem value="java" label="Java" default>

```java showLineNumbers
Map<String, String> customTags = new HashMap<>();
customTags.put("USERNAME", "John");
AdaptyUiTagResolver tagResolver = customTags::get;
```

</TabItem>
</Tabs>

Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme `<USERNAME/>`. 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"

<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar">

    <item name="adapty_progressIndicatorColor">@color/yourColor</item>
</style>
```

---

> [!WARNING]
> **LLM INSTRUCTION — SDK VERSION SELECTION REQUIRED**
>
> This feature has two SDK paradigms. Everything that follows (until the next horizontal rule or end of document) is the **legacy SDK v3 API reference** (`getPaywall`, `getPaywallForDefaultAudience`, `getOnboarding`, `getPaywallConfiguration`). The **SDK v4+ `getFlow` method is documented above.** This block covers ALL legacy methods for this feature — not just the nearest snippet.
>
> **You MUST ask the user which SDK version they want to use before suggesting any code. Do not assume or default to a version.** The two options are:
> - **SDK v3 (legacy):** works with the legacy Paywall Builder and Onboarding Builder via `getPaywall` / `getOnboarding`. Use the legacy code in this section.
> - **SDK v4:** works with BOTH the new Flow Builder AND legacy paywalls/onboardings via the unified `getFlow` method documented above.
>
> Apply the legacy v3 code in this section ONLY when:
> 1. The user explicitly chose **SDK v3**, or
> 2. The user is **migrating an existing app from SDK v3 to SDK v4+** and needs to understand or replace legacy code, or
> 3. The user is **troubleshooting an already-deployed v3 integration**.
>
> **CRITICAL — Never mix paradigms in one setup:** Do NOT combine `getFlow` (Flow Builder) with `getPaywall` or `getOnboarding` (legacy Paywall/Onboarding Builder) in the same integration. These are incompatible patterns. Mixing them will produce inconsistent behavior and is unsupported.

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

<Tabs groupId="current-os" queryString>
<TabItem value="views" label="Views" default>

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

<Tabs groupId="current-os" queryString>
  <TabItem value="kotlin" label="Kotlin (option 1)" default>

```kotlin showLineNumbers
   val paywallView = AdaptyUI.getPaywallView(
       activity,
       viewConfiguration,
       products,
       eventListener,
       insets,
       personalizedOfferResolver,
       tagResolver,
       timerResolver,
   )
```
</TabItem>
<TabItem value="kotlin2" label="Kotlin (option 2)" default>

```kotlin showLineNumbers
   val paywallView =
        AdaptyPaywallView(activity) // or retrieve it from xml
   ...
   with(paywallView) {
       showPaywall(
           viewConfiguration,
           products,
					 eventListener,
           insets,
           personalizedOfferResolver,
           tagResolver,
           timerResolver,
       )
   }
```

</TabItem>
<TabItem value="java" label="Java (option 1)" default>

```java showLineNumbers
AdaptyPaywallView paywallView = AdaptyUI.getPaywallView(
        activity,
        viewConfiguration,
        products,
        eventListener,
        insets,
        personalizedOfferResolver,
        tagResolver,
        timerResolver
);
```
</TabItem>
<TabItem value="java2" label="Java (option 2)" default>

```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);
```

</TabItem>
<TabItem value="XML" label="XML" default>

```xml showLineNumbers
<com.adapty.ui.AdaptyPaywallView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```
</TabItem>
</Tabs>

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()`.

</TabItem>
<TabItem value="compose" label="Jetpack Compose" default>

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,
)
```
</TabItem>
</Tabs>

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 | <p>Les insets sont les espaces autour du paywall qui empêchent les éléments cliquables d'être masqués par les barres système.</p><p>Par défaut : `UNSPECIFIED`, ce qui signifie qu'Adapty ajustera automatiquement les insets, ce qui fonctionne parfaitement pour les paywalls plein écran. </p><p>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.</p> |
| **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 :

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>
```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,
       )
}
```
</TabItem>
<TabItem value="java" label="Java" default>
```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;
});
```
</TabItem>
</Tabs>

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

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```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 */ } )
}
```

</TabItem>
<TabItem value="java" label="Java" default>

```java showLineNumbers

...

Map<String, Date> 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 */
    }
};
```

</TabItem>

</Tabs>

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 :

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```kotlin showLineNumbers
val customTags = mapOf("USERNAME" to "John")
val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] }
```

</TabItem>
<TabItem value="java" label="Java" default>

```java showLineNumbers
Map<String, String> customTags = new HashMap<>();
customTags.put("USERNAME", "John");
AdaptyUiTagResolver tagResolver = customTags::get;
```

</TabItem>
</Tabs>

Dans cet exemple, `USERNAME` est une balise personnalisée que vous avez saisie dans l'Adapty Dashboard sous la forme `<USERNAME/>`. 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"

<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar">

    <item name="adapty_progressIndicatorColor">@color/yourColor</item>
</style>
```

---