# Live Updates en Android

Pushwoosh es compatible con las Live Updates de Android a través del módulo `pushwoosh-liveupdates` (SDK 6.9.0 y posteriores). Una Live Update es una notificación continua, de estilo de progreso, que el sistema promociona en la pantalla de bloqueo, en el cajón de notificaciones y como un chip de estado en la barra de estado, para que los usuarios puedan seguir una actividad sin abrir tu aplicación.

Todo el ciclo de vida se gestiona desde el servidor: tu backend envía un push cuando la actividad comienza, más pushes a medida que avanza y un push final cuando termina. El SDK renderiza cada uno automáticamente.

## ¿Qué son las Live Updates?

Las Live Updates se introdujeron en Android 16 (API 36) como una forma de mostrar una actividad iniciada por el usuario y sensible al tiempo de principio a fin. Se basan en las notificaciones centradas en el progreso de la plataforma y en la API `Notification.ProgressStyle`. Conceptualmente, son la contraparte en Android de las Live Activities de iOS.

Esta página cubre únicamente la integración con Pushwoosh. Para conocer el comportamiento de la plataforma, las reglas de promoción y las guías de diseño, consulta la documentación oficial de Android:

- [Notificaciones centradas en el progreso](https://developer.android.com/about/versions/16/features/progress-centric-notifications)
- [Crear notificaciones de actualización en vivo (Views)](https://developer.android.com/develop/ui/views/notifications/live-update)
- [Crear notificaciones de actualización en vivo (Compose)](https://developer.android.com/develop/ui/compose/notifications/live-update)

## ¿Cuándo usar las Live Updates?

Las Live Updates están pensadas para una actividad que está en curso, iniciada por el usuario y es sensible al tiempo; algo con un inicio y un final claros que al usuario le importa activamente en este momento. Escenarios típicos para los clientes de Pushwoosh:

- **Entrega de comida** — pedido aceptado, en preparación, en camino, llegando.
- **Servicios de transporte y taxi** — conductor asignado, en ruta, llegando, viaje en curso.
- **Seguimiento de pedidos y envíos** — estado en vivo de un pedido que está activamente en tránsito.
- **Deportes y medios en vivo** — marcador y tiempo del partido a medida que se desarrolla el juego.
- **Fitness** — un entrenamiento o carrera activa con tiempo transcurrido y progreso.
- **Fintech** — un flujo de transacción o verificación que avanza por sus etapas.

Debido a que el ciclo de vida es impulsado por eventos reales que tu backend ya conoce (un pedido cambia de estado, un mensajero se mueve), una Live Update suele ser una llamada a la API conectada a tu flujo de eventos existente, no algo que una persona envía manualmente.

<Aside type="caution">
No utilices las Live Updates para promociones, mensajes de chat o información ambiental, y nunca vuelvas a publicar una Live Update que el usuario haya descartado. Android puede revocar la capacidad de la aplicación para publicar notificaciones promocionadas. Sigue la [guía de Android sobre el uso apropiado](https://developer.android.com/develop/ui/views/notifications/live-update#best-practices).
</Aside>

## Requisitos

- Android 16 (API 36) o superior. En dispositivos más antiguos, el módulo permanece inactivo y cada llamada a la API de Live Update es una operación segura que no hace nada (no-op).
- Pushwoosh Android SDK 6.9.0 o posterior.

## Añadir el módulo pushwoosh-liveupdates

Añade la dependencia a tu **app/build.gradle**:

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

Reemplaza `<latest-version>` con la versión actual de [Maven Central](https://mvnrepository.com/artifact/com.pushwoosh/pushwoosh-liveupdates).

El módulo se descubre automáticamente al iniciar. Declara el permiso requerido `POST_PROMOTED_NOTIFICATIONS`, registra su propio canal de notificaciones e intercepta los pushes de Live Update antes de la ruta de notificación predeterminada. No hay código de inicialización adicional: el SDK establece los indicadores de `ongoing` y `promoted`, descarga el icono grande, mapea los botones de acción y publica la notificación por ti.

## Enviar una Live Update

Envías Live Updates a través de la [API de Mensajería v2](/es/developer/api-reference/messaging-api-v2/) añadiendo un objeto `live_update` al bloque de contenido `android`. Utiliza una solicitud `transactional`: una Live Update se dirige al usuario específico cuya actividad está rastreando. El campo `schedule` es obligatorio; `{ "after": "0s" }` envía inmediatamente. El ciclo de vida tiene tres operaciones, establecidas en `live_update.op`:

- `OPERATION_START` — primer push para una actividad. Publica la notificación en curso.
- `OPERATION_UPDATE` — un push posterior para la misma actividad. La actualiza en el mismo lugar, de forma silenciosa.
- `OPERATION_END` — push terminal. Descarta la notificación.

Todos los pushes que pertenecen a la misma actividad deben compartir el mismo `live_update.id`. Ese id une las actualizaciones y también es lo que usas para descartar la actualización desde la aplicación.

Cada push describe completamente la notificación; nada se hereda del push anterior. Vuelve a enviar cada campo que quieras conservar, como los segmentos y el icono grande, con cada `OPERATION_UPDATE`; un campo omitido se renderiza como ausente.

### Parámetros de Live Update

Estas claves van dentro del objeto `live_update` del bloque de contenido `android`. El título, el cuerpo y el icono grande utilizan los campos de push estándar de Android (`title`, `body`, `custom_icon`), enviados junto con `live_update`.

| Parámetro | Tipo | Descripción |
|---|---|---|
| `op` | string | Operación del ciclo de vida: `OPERATION_START`, `OPERATION_UPDATE` o `OPERATION_END`. Obligatorio. |
| `id` | string | ID de actividad estable compartido por todos los pushes de una Live Update. Obligatorio. |
| `progress` | int | Valor de progreso, medido contra la suma de las longitudes de los segmentos. |
| `progress_indeterminate` | bool | Muestra una animación indeterminada en lugar de un valor concreto. |
| `progress_bar` | bool | Muestra la barra de progreso. El valor predeterminado es `true`. |
| `segments` | array | Segmentos de progreso ordenados, cada uno `{ "color": "#RRGGBB", "length": N }`. |
| `extras` | object | Datos arbitrarios pasados a un proveedor de estilo personalizado. |
| `when` | int64 | Ancla de tiempo del encabezado, en milisegundos de la época (epoch). |
| `chronometer` | bool | Muestra el tiempo del encabezado como un cronómetro en funcionamiento. |
| `chronometer_count_down` | bool | Un cronómetro en funcionamiento cuenta hacia atrás en lugar de hacia adelante. |
| `show_when` | bool | Muestra la columna de tiempo del encabezado. El valor predeterminado es `true`. |

<Aside>
El valor de `op` debe ser uno de los nombres exactos del enum `OPERATION_START`, `OPERATION_UPDATE` o `OPERATION_END`; las formas abreviadas se ignoran. Cada campo lleva su tipo JSON nativo: `segments` es un array JSON y `extras` un objeto JSON, no cadenas codificadas.
</Aside>

Los cuatro campos de tiempo se combinan de la siguiente manera: con `show_when` establecido en `false`, el tiempo se oculta; de lo contrario, `when` es el ancla, `chronometer` lo convierte en un contador en vivo, y `chronometer_count_down` hace que ese contador vaya hacia atrás.

### Push de inicio

```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 actualización

Envía un `OPERATION_UPDATE` con el mismo `id` cada vez que la actividad avance. Repite los segmentos y el icono; una actualización que los omita se renderizará sin ellos.

```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 finalización

El push terminal solo necesita la operación y el id.

```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"
    }
  }'
```

## Personalizar la apariencia

El SDK incluye un estilo de progreso predeterminado construido a partir de `progress`, `progress_indeterminate` y `segments`. Para tener control total sobre la barra de progreso, implementa `LiveUpdateProgressStyleProvider` y da forma a un `Notification.ProgressStyle` tú mismo.

El proveedor es el único punto de personalización. El SDK sigue siendo responsable de la configuración del canal, los indicadores de `ongoing` y `promoted`, el icono grande, los botones de acción y el tiempo del encabezado; un proveedor personalizado solo puede dar forma a la barra de progreso, por lo que no puede romper la elegibilidad para la promoción. Debe ser sin estado (stateless): deriva el estilo devuelto únicamente del `LiveUpdateState` proporcionado. Si lanza una excepción, el SDK recurre al estilo predeterminado y la notificación se publica de todos modos.

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

Registra el proveedor con una etiqueta `<meta-data>` en **AndroidManifest.xml**. La clase debe tener un constructor público sin argumentos.

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

Usa `LiveUpdateState.getExtras()` para leer el JSON que enviaste en `live_update.extras` y adaptar el estilo a tus propios datos de negocio.

## Gestionar Live Updates desde tu aplicación

El servidor impulsa cada `OPERATION_START`, `OPERATION_UPDATE` y `OPERATION_END`, por lo que no hay una API del lado de la aplicación para publicar o actualizar una Live Update. La fachada `PushwooshLiveUpdates` cubre solo lo que el servidor no puede hacer: descartar una actualización localmente y verificar cuáles están en pantalla.

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

// Descarta una Live Update específica cuando el usuario finaliza la actividad en la aplicación,
// sin esperar el push terminal "end" del servidor
PushwooshLiveUpdates.endLiveUpdate("order_4521");

// Lista los IDs de actividad que esta aplicación muestra actualmente
List<String> active = PushwooshLiveUpdates.getActiveIds();

// Borra todo lo que esta aplicación está mostrando, por ejemplo, al cerrar sesión
PushwooshLiveUpdates.endAllLiveUpdates();
```

Todos los métodos son seguros para llamar desde cualquier hilo y son una operación que no hace nada (no-op) en dispositivos por debajo de Android 16.

## Enlaces relacionados

- [Visión general del SDK de Android de Pushwoosh](/es/developer/pushwoosh-sdk/android-sdk/)
- [Referencia de la API del SDK de Android de Pushwoosh](https://pushwoosh.github.io/pushwoosh-android-sdk/)
- [API de Mensajería](/es/developer/api-reference/messaging-api-v2/)
- [Notificaciones centradas en el progreso de Android](https://developer.android.com/about/versions/16/features/progress-centric-notifications)