# Mises à jour en direct sur Android

Pushwoosh prend en charge les mises à jour en direct d'Android via le module `pushwoosh-liveupdates` (SDK 6.9.0 et versions ultérieures). Une mise à jour en direct est une notification continue de type progression que le système met en avant sur l'écran de verrouillage, dans le tiroir de notifications et sous forme de puce d'état dans la barre d'état, afin que les utilisateurs puissent suivre une activité sans ouvrir votre application.

L'ensemble du cycle de vie est piloté depuis le serveur : votre backend envoie une notification push lorsque l'activité commence, d'autres notifications push au fur et à mesure de sa progression, et une dernière notification push lorsqu'elle se termine. Le SDK effectue le rendu de chacune d'entre elles automatiquement.

## Que sont les mises à jour en direct ?

Les mises à jour en direct ont été introduites dans Android 16 (API 36) comme un moyen de présenter une activité initiée par l'utilisateur et sensible au temps, du début à la fin. Elles s'appuient sur les notifications axées sur la progression de la plateforme et sur l'API `Notification.ProgressStyle`. Conceptuellement, elles sont l'équivalent Android des Live Activities d'iOS.

Cette page ne couvre que l'intégration de Pushwoosh. Pour le comportement de la plateforme, les règles de promotion et les conseils de conception, consultez la documentation officielle d'Android :

- [Notifications axées sur la progression](https://developer.android.com/about/versions/16/features/progress-centric-notifications)
- [Créer des notifications de mise à jour en direct (Vues)](https://developer.android.com/develop/ui/views/notifications/live-update)
- [Créer des notifications de mise à jour en direct (Compose)](https://developer.android.com/develop/ui/compose/notifications/live-update)

## Quand utiliser les mises à jour en direct ?

Les mises à jour en direct sont destinées à une activité en cours, initiée par l'utilisateur et sensible au temps — quelque chose avec un début et une fin clairs qui intéresse activement l'utilisateur à l'instant T. Scénarios typiques pour les clients de Pushwoosh :

- **Livraison de repas** — commande acceptée, en préparation, en cours de livraison, en approche.
- **VTC et taxi** — chauffeur assigné, en route, en approche, trajet en cours.
- **Suivi de commande et d'expédition** — statut en direct d'une commande qui est activement en transit.
- **Sports et médias en direct** — score et temps du match au fur et à mesure de son déroulement.
- **Fitness** — un entraînement ou une course en cours avec le temps écoulé et la progression.
- **Fintech** — une transaction ou un flux de vérification passant par ses différentes étapes.

Étant donné que le cycle de vie est piloté par des événements réels que votre backend connaît déjà (une commande change de statut, un coursier se déplace), une mise à jour en direct correspond généralement à un seul appel d'API intégré à votre flux d'événements existant — et non à quelque chose qu'une personne envoie manuellement.

<Aside type="caution">
N'utilisez pas les mises à jour en direct pour des promotions, des messages de chat ou des informations ambiantes, et ne republiez jamais une mise à jour en direct que l'utilisateur a rejetée. Android peut révoquer la capacité de l'application à publier des notifications promues. Suivez les [directives d'Android sur l'utilisation appropriée](https://developer.android.com/develop/ui/views/notifications/live-update#best-practices).
</Aside>

## Prérequis

- Android 16 (API 36) ou plus récent. Sur les appareils plus anciens, le module reste inactif et chaque appel d'API de mise à jour en direct est une opération sans effet (no-op) sécurisée.
- SDK Android Pushwoosh 6.9.0 ou version ultérieure.

## Ajouter le module pushwoosh-liveupdates

Ajoutez la dépendance à votre fichier **app/build.gradle** :

```groovy
dependencies {
    implementation 'com.pushwoosh:pushwoosh-liveupdates:<latest-version>'
}
```

Remplacez `<latest-version>` par la version actuelle de [Maven Central](https://mvnrepository.com/artifact/com.pushwoosh/pushwoosh-liveupdates).

Le module est découvert automatiquement au démarrage. Il déclare l'autorisation `POST_PROMOTED_NOTIFICATIONS` requise, enregistre son propre canal de notification et intercepte les notifications push de mise à jour en direct avant le chemin de notification par défaut. Il n'y a pas de code d'initialisation supplémentaire — le SDK définit les indicateurs `ongoing` et `promoted`, télécharge la grande icône, mappe les boutons d'action et publie la notification pour vous.

## Envoyer une mise à jour en direct

Vous envoyez des mises à jour en direct via l'[API de messagerie v2](/fr/developer/api-reference/messaging-api-v2/) en ajoutant un objet `live_update` au bloc de contenu `android`. Utilisez une requête `transactional` — une mise à jour en direct cible l'utilisateur spécifique dont elle suit l'activité. Le champ `schedule` est requis ; `{ "after": "0s" }` envoie immédiatement. Le cycle de vie comporte trois opérations, définies dans `live_update.op` :

- `OPERATION_START` — premier push pour une activité. Publie la notification en cours.
- `OPERATION_UPDATE` — un push ultérieur pour la même activité. La rafraîchit sur place, silencieusement.
- `OPERATION_END` — push terminal. Rejette la notification.

Tous les pushes appartenant à la même activité doivent partager le même `live_update.id`. Cet identifiant relie les mises à jour entre elles et c'est aussi ce que vous utilisez pour rejeter la mise à jour depuis l'application.

Chaque push décrit entièrement la notification — rien n'est repris du push précédent. Renvoyez chaque champ que vous souhaitez conserver, comme les segments et la grande icône, avec chaque `OPERATION_UPDATE` ; un champ omis est rendu comme absent.

### Paramètres de la mise à jour en direct

Ces clés vont à l'intérieur de l'objet `live_update` du bloc de contenu `android`. Le titre, le corps et la grande icône utilisent les champs de push Android standard (`title`, `body`, `custom_icon`), envoyés en même temps que `live_update`.

| Paramètre | Type | Description |
|---|---|---|
| `op` | chaîne | Opération du cycle de vie : `OPERATION_START`, `OPERATION_UPDATE` ou `OPERATION_END`. Requis. |
| `id` | chaîne | ID d'activité stable partagé par tous les pushes d'une même mise à jour en direct. Requis. |
| `progress` | entier | Valeur de progression, mesurée par rapport à la somme des longueurs des segments. |
| `progress_indeterminate` | booléen | Affiche une animation indéterminée au lieu d'une valeur concrète. |
| `progress_bar` | booléen | Affiche ou non la barre de progression. La valeur par défaut est `true`. |
| `segments` | tableau | Segments de progression ordonnés, chacun sous la forme `{ "color": "#RRGGBB", "length": N }`. |
| `extras` | objet | Données arbitraires transmises à un fournisseur de style personnalisé. |
| `when` | int64 | Ancre temporelle de l'en-tête, en millisecondes d'époque. |
| `chronometer` | booléen | Affiche l'heure de l'en-tête sous forme de chronomètre en cours. |
| `chronometer_count_down` | booléen | Un chronomètre en cours décompte au lieu de compter. |
| `show_when` | booléen | Affiche ou non la colonne de l'heure de l'en-tête. La valeur par défaut est `true`. |

<Aside>
La valeur de `op` doit être l'un des noms d'énumération exacts `OPERATION_START`, `OPERATION_UPDATE` ou `OPERATION_END` — les formes courtes sont ignorées. Chaque champ porte son type JSON natif : `segments` est un tableau JSON et `extras` un objet JSON, et non des chaînes encodées.
</Aside>

Les quatre champs temporels se combinent comme suit : avec `show_when` défini sur `false`, l'heure est masquée ; sinon, `when` est l'ancre, `chronometer` la transforme en un compteur en direct, et `chronometer_count_down` fait que ce compteur fonctionne à rebours.

### Push de démarrage

```bash
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transactional": {
      "application": "XXXXX-XXXXX",
      "platforms": ["ANDROID"],
      "users": { "list": ["customer-42"] },
      "payload": {
        "content": {
          "localized_content": {
            "default": {
              "android": {
                "title": "Order #4521",
                "body": "We are preparing your order",
                "custom_icon": "https://example.com/restaurant.png",
                "live_update": {
                  "op": "OPERATION_START",
                  "id": "order_4521",
                  "progress": 1,
                  "segments": [
                    { "color": "#34A853", "length": 3 },
                    { "color": "#FBBC05", "length": 4 },
                    { "color": "#4285F4", "length": 3 }
                  ],
                  "extras": { "eta": "18:40" }
                }
              }
            }
          }
        }
      },
      "schedule": { "after": "0s" },
      "message_type": "MESSAGE_TYPE_TRANSACTIONAL"
    }
  }'
```

### Push de mise à jour

Envoyez une `OPERATION_UPDATE` avec le même `id` chaque fois que l'activité progresse. Répétez les segments et l'icône — une mise à jour qui les omet s'affichera sans eux.

```bash
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transactional": {
      "application": "XXXXX-XXXXX",
      "platforms": ["ANDROID"],
      "users": { "list": ["customer-42"] },
      "payload": {
        "content": {
          "localized_content": {
            "default": {
              "android": {
                "title": "Order #4521",
                "body": "Your courier is on the way",
                "custom_icon": "https://example.com/restaurant.png",
                "live_update": {
                  "op": "OPERATION_UPDATE",
                  "id": "order_4521",
                  "progress": 7,
                  "segments": [
                    { "color": "#34A853", "length": 3 },
                    { "color": "#FBBC05", "length": 4 },
                    { "color": "#4285F4", "length": 3 }
                  ]
                }
              }
            }
          }
        }
      },
      "schedule": { "after": "0s" },
      "message_type": "MESSAGE_TYPE_TRANSACTIONAL"
    }
  }'
```

### Push de fin

Le push terminal n'a besoin que de l'opération et de l'identifiant.

```bash
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transactional": {
      "application": "XXXXX-XXXXX",
      "platforms": ["ANDROID"],
      "users": { "list": ["customer-42"] },
      "payload": {
        "content": {
          "localized_content": {
            "default": {
              "android": {
                "live_update": {
                  "op": "OPERATION_END",
                  "id": "order_4521"
                }
              }
            }
          }
        }
      },
      "schedule": { "after": "0s" },
      "message_type": "MESSAGE_TYPE_TRANSACTIONAL"
    }
  }'
```

## Personnaliser l'apparence

Le SDK est livré avec un style de progression par défaut construit à partir de `progress`, `progress_indeterminate` et `segments`. Pour prendre le contrôle total de la barre de progression, implémentez `LiveUpdateProgressStyleProvider` et façonnez vous-même un `Notification.ProgressStyle`.

Le fournisseur est le seul point de personnalisation. Le SDK gère toujours la configuration du canal, les indicateurs `ongoing` et `promoted`, la grande icône, les boutons d'action et l'heure de l'en-tête — un fournisseur personnalisé ne peut que façonner la barre de progression, il ne peut donc pas rompre l'éligibilité à la promotion. Il doit être sans état : dérivez le style retourné uniquement à partir du `LiveUpdateState` fourni. S'il lève une exception, le SDK se rabat sur le style par défaut et la notification est quand même publiée.

<Tabs>
<TabItem label="Java">
```java
import android.app.Notification;
import androidx.annotation.NonNull;
import com.pushwoosh.liveupdates.LiveUpdateProgressStyleProvider;
import com.pushwoosh.liveupdates.LiveUpdateSegment;
import com.pushwoosh.liveupdates.LiveUpdateState;
import java.util.List;

public class OrderStyleProvider implements LiveUpdateProgressStyleProvider {
    @NonNull
    @Override
    public Notification.ProgressStyle createStyle(@NonNull LiveUpdateState state) {
        Notification.ProgressStyle style = new Notification.ProgressStyle();
        if (state.getProgress() != null) {
            style.setProgress(state.getProgress());
        }
        style.setProgressIndeterminate(state.isProgressIndeterminate());

        List<LiveUpdateSegment> segments = state.getSegments();
        int boundary = 0;
        for (int i = 0; i < segments.size(); i++) {
            LiveUpdateSegment seg = segments.get(i);
            style.addProgressSegment(
                new Notification.ProgressStyle.Segment(seg.getLength()).setColor(seg.getColor()));
            boundary += seg.getLength();
            if (i < segments.size() - 1) {
                style.addProgressPoint(new Notification.ProgressStyle.Point(boundary));
            }
        }
        return style;
    }
}
```
</TabItem>
<TabItem label="Kotlin">
```kotlin
import android.app.Notification
import com.pushwoosh.liveupdates.LiveUpdateProgressStyleProvider
import com.pushwoosh.liveupdates.LiveUpdateState

class OrderStyleProvider : LiveUpdateProgressStyleProvider {
    override fun createStyle(state: LiveUpdateState): Notification.ProgressStyle {
        val style = Notification.ProgressStyle()
        state.progress?.let { style.setProgress(it) }
        style.setProgressIndeterminate(state.isProgressIndeterminate)

        val segments = state.segments
        var boundary = 0
        segments.forEachIndexed { i, seg ->
            style.addProgressSegment(
                Notification.ProgressStyle.Segment(seg.length).setColor(seg.color))
            boundary += seg.length
            if (i < segments.size - 1) {
                style.addProgressPoint(Notification.ProgressStyle.Point(boundary))
            }
        }
        return style
    }
}
```
</TabItem>
</Tabs>

Enregistrez le fournisseur avec une balise `<meta-data>` dans **AndroidManifest.xml**. La classe doit avoir un constructeur public sans argument.

```xml
<meta-data
    android:name="com.pushwoosh.LIVE_UPDATE_STYLE_PROVIDER"
    android:value="com.example.OrderStyleProvider" />
```

Utilisez `LiveUpdateState.getExtras()` pour lire le JSON que vous avez envoyé dans `live_update.extras` et adapter le style à vos propres données métier.

## Gérer les mises à jour en direct depuis votre application

Le serveur pilote chaque `OPERATION_START`, `OPERATION_UPDATE` et `OPERATION_END`, il n'y a donc pas d'API côté application pour publier ou rafraîchir une mise à jour en direct. La façade `PushwooshLiveUpdates` ne couvre que ce que le serveur ne peut pas faire — rejeter une mise à jour localement et vérifier lesquelles sont à l'écran.

```java
import com.pushwoosh.liveupdates.PushwooshLiveUpdates;

// Rejeter une mise à jour en direct spécifique lorsque l'utilisateur termine l'activité dans l'application,
// sans attendre le push terminal "end" du serveur
PushwooshLiveUpdates.endLiveUpdate("order_4521");

// Lister les identifiants d'activité actuellement affichés par cette application
List<String> active = PushwooshLiveUpdates.getActiveIds();

// Effacer tout ce que cette application affiche, par exemple lors de la déconnexion
PushwooshLiveUpdates.endAllLiveUpdates();
```

Toutes les méthodes peuvent être appelées en toute sécurité depuis n'importe quel thread et sont des opérations sans effet (no-op) sur les appareils inférieurs à Android 16.

## Liens connexes

- [Aperçu du SDK Android de Pushwoosh](/fr/developer/pushwoosh-sdk/android-sdk/)
- [Référence de l'API du SDK Android de Pushwoosh](https://pushwoosh.github.io/pushwoosh-android-sdk/)
- [API de messagerie](/fr/developer/api-reference/messaging-api-v2/)
- [Notifications Android axées sur la progression](https://developer.android.com/about/versions/16/features/progress-centric-notifications)