Live Updates на Android
Pushwoosh поддерживает Live Updates на Android через модуль pushwoosh-liveupdates (SDK 6.9.0 и новее). Live Update — это непрерывное уведомление в стиле прогресс-бара, которое система выводит на экран блокировки, в панель уведомлений и в виде чипа состояния в строке состояния, чтобы пользователи могли следить за активностью, не открывая ваше приложение.
Весь жизненный цикл управляется с сервера: ваш бэкенд отправляет push-уведомление, когда активность начинается, новые push-уведомления по мере ее продвижения и финальное push-уведомление, когда она заканчивается. SDK отображает каждое из них автоматически.
Что такое Live Updates
Anchor link toLive Updates были представлены в Android 16 (API 36) как способ отображения инициированной пользователем, чувствительной ко времени активности от начала до конца. Они основаны на уведомлениях платформы, ориентированных на прогресс, и API Notification.ProgressStyle. Концептуально они являются аналогом Live Activities в iOS.
Эта страница описывает только интеграцию с Pushwoosh. Для получения информации о поведении платформы, правилах продвижения и рекомендациях по дизайну обратитесь к официальной документации Android:
- Уведомления, ориентированные на прогресс
- Создание интерактивных уведомлений (Views)
- Создание интерактивных уведомлений (Compose)
Когда использовать Live Updates
Anchor link toLive Updates предназначены для непрерывной, инициированной пользователем и чувствительной ко времени активности — чего-то с четким началом и концом, что важно пользователю прямо сейчас. Типичные сценарии для клиентов Pushwoosh:
- Доставка еды — заказ принят, готовится, в пути, прибывает.
- Вызов такси — водитель назначен, в пути, прибывает, поездка в процессе.
- Отслеживание заказов и посылок — актуальный статус заказа, который находится в пути.
- Спортивные трансляции и медиа — счет и время матча в реальном времени.
- Фитнес — активная тренировка или пробежка с отображением прошедшего времени и прогресса.
- Финтех — транзакция или процесс верификации, проходящий через свои этапы.
Поскольку жизненный цикл управляется реальными событиями, о которых ваш бэкенд уже знает (статус заказа меняется, курьер движется), Live Update обычно представляет собой один вызов API, встроенный в ваш существующий поток событий, а не что-то, что человек отправляет вручную.
Требования
Anchor link to- Android 16 (API 36) или новее. На старых устройствах модуль остается неактивным, и каждый вызов API Live Update является безопасной пустой операцией (no-op).
- Pushwoosh Android SDK 6.9.0 или новее.
Добавьте модуль pushwoosh-liveupdates
Anchor link toДобавьте зависимость в ваш файл app/build.gradle:
dependencies { implementation 'com.pushwoosh:pushwoosh-liveupdates:<latest-version>'}Замените <latest-version> на текущую версию из Maven Central.
Модуль обнаруживается автоматически при запуске. Он объявляет необходимое разрешение POST_PROMOTED_NOTIFICATIONS, регистрирует собственный канал уведомлений и перехватывает push-уведомления Live Update до стандартного пути обработки уведомлений. Дополнительный код инициализации не требуется — SDK устанавливает флаги ongoing и promoted, загружает большую иконку, сопоставляет кнопки действий и публикует уведомление за вас.
Отправка Live Update
Anchor link toВы отправляете Live Updates через Messaging API v2, добавляя объект live_update в блок контента android. Используйте transactional запрос — Live Update нацелен на конкретного пользователя, чью активность он отслеживает. Поле schedule является обязательным; { "after": "0s" } отправляет немедленно. Жизненный цикл имеет три операции, устанавливаемые в live_update.op:
OPERATION_START— первое push-уведомление для активности. Публикует непрерывное уведомление.OPERATION_UPDATE— последующее push-уведомление для той же активности. Обновляет его на месте беззвучно.OPERATION_END— завершающее push-уведомление. Отклоняет уведомление.
Все push-уведомления, относящиеся к одной и той же активности, должны иметь одинаковый live_update.id. Этот идентификатор связывает обновления вместе, а также используется для отклонения обновления из приложения.
Каждое push-уведомление полностью описывает уведомление — ничего не переносится из предыдущего. Повторно отправляйте каждое поле, которое хотите сохранить, например, сегменты и большую иконку, с каждым OPERATION_UPDATE; пропущенное поле будет отображаться как отсутствующее.
Параметры Live Update
Anchor link toЭти ключи помещаются внутрь объекта live_update в блоке контента android. Заголовок, текст и большая иконка используют стандартные поля Android push-уведомлений (title, body, custom_icon), отправляемые вместе с live_update.
| Параметр | Тип | Описание |
|---|---|---|
op | string | Операция жизненного цикла: OPERATION_START, OPERATION_UPDATE или OPERATION_END. Обязательно. |
id | string | Стабильный идентификатор активности, общий для всех push-уведомлений одного Live Update. Обязательно. |
progress | int | Значение прогресса, измеряемое относительно суммарной длины сегментов. |
progress_indeterminate | bool | Показывать неопределенную анимацию вместо конкретного значения. |
progress_bar | bool | Показывать ли прогресс-бар. По умолчанию true. |
segments | array | Упорядоченные сегменты прогресса, каждый в формате { "color": "#RRGGBB", "length": N }. |
extras | object | Произвольные данные, передаваемые в кастомный провайдер стилей. |
when | int64 | Временная метка заголовка в миллисекундах эпохи. |
chronometer | bool | Показывать время в заголовке как работающий таймер. |
chronometer_count_down | bool | Работающий таймер ведет обратный отсчет, а не прямой. |
show_when | bool | Показывать ли столбец времени в заголовке. По умолчанию true. |
Четыре поля времени комбинируются следующим образом: если show_when установлено в false, время скрыто; в противном случае when является точкой отсчета, chronometer превращает его в работающий счетчик, а chronometer_count_down заставляет этот счетчик идти в обратном направлении.
Стартовое push-уведомление
Anchor link tocurl -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-уведомление
Anchor link toОтправляйте OPERATION_UPDATE с тем же id каждый раз, когда активность продвигается. Повторяйте сегменты и иконку — обновление, в котором они отсутствуют, будет отображено без них.
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-уведомление
Anchor link toЗавершающему push-уведомлению нужны только операция и идентификатор.
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" } }'Кастомизация внешнего вида
Anchor link toSDK поставляется с дефолтным стилем прогресса, построенным из progress, progress_indeterminate и segments. Чтобы получить полный контроль над прогресс-баром, реализуйте LiveUpdateProgressStyleProvider и самостоятельно сформируйте Notification.ProgressStyle.
Провайдер — это единственная точка кастомизации. SDK по-прежнему управляет настройкой канала, флагами ongoing и promoted, большой иконкой, кнопками действий и временем в заголовке — кастомный провайдер может формировать только прогресс-бар, поэтому он не может нарушить право на продвижение. Он должен быть без состояния (stateless): возвращаемый стиль должен быть получен только из предоставленного LiveUpdateState. Если он выбрасывает исключение, SDK возвращается к дефолтному стилю, и уведомление все равно публикуется.
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; }}import android.app.Notificationimport com.pushwoosh.liveupdates.LiveUpdateProgressStyleProviderimport 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 }}Зарегистрируйте провайдер с помощью тега <meta-data> в AndroidManifest.xml. Класс должен иметь публичный конструктор без аргументов.
<meta-data android:name="com.pushwoosh.LIVE_UPDATE_STYLE_PROVIDER" android:value="com.example.OrderStyleProvider" />Используйте LiveUpdateState.getExtras() для чтения JSON, который вы отправили в live_update.extras, и адаптируйте стиль к вашим собственным бизнес-данным.
Управление Live Updates из вашего приложения
Anchor link toСервер управляет каждым OPERATION_START, OPERATION_UPDATE и OPERATION_END, поэтому нет API на стороне приложения для публикации или обновления Live Update. Фасад PushwooshLiveUpdates охватывает только то, что не может сделать сервер — локальное отклонение обновления и проверка, какие из них отображаются на экране.
import com.pushwoosh.liveupdates.PushwooshLiveUpdates;
// Отклонить конкретный Live Update, когда пользователь завершает активность в приложении,// не дожидаясь завершающего push-уведомления "end" от сервераPushwooshLiveUpdates.endLiveUpdate("order_4521");
// Получить список идентификаторов активностей, отображаемых в данный момент этим приложениемList<String> active = PushwooshLiveUpdates.getActiveIds();
// Очистить все, что отображает это приложение, например, при выходе из системыPushwooshLiveUpdates.endAllLiveUpdates();Все методы безопасны для вызова из любого потока и являются пустой операцией (no-op) на устройствах ниже Android 16.