Разработка
Live Updates в Android 16 — исследуем новые уведомления
Начиная с Android 16, у нас появился новый стиль уведомлений Notification.ProgressStyle, который мы можем использовать для создания уведомлений, ориентированных на отображение прогресса выполнения задач.
Начиная с Android 16, у нас появился новый стиль уведомлений Notification.ProgressStyle
, который мы можем использовать для создания уведомлений, ориентированных на отображение прогресса выполнения задач.
В этой статье мы узнаем, как использовать этот новый стиль для предоставления конечным пользователям оперативных обновлений.
Важные сценарии использования, которые мы можем реализовать с помощью этого стиля, следующие
- Райдшаринг
- Доставка еды
- Навигация
- И т.д.
ProgressStyle довольно настраиваемый. Он включает в себя следующие компоненты, которые мы можем использовать для предоставления конечным пользователям возможности получать обновления в режиме реального времени:
- Индикатора прогресса — прогресс бар
- Сегменты — части прогресс бара с длинной и цветом
- Точки — отметки внутри индикатора прогресса с положением и цветом
- Иконки трекера
- Иконки начала и конца для индикатора прогресса
Реализация
В файле build.gradle приложения установите SDK компиляции на Android 16.
android { // Android 16 compileSdk = 36 defaultConfig { minSdk = 29 // Android 16 targetSdk = 36 } }
Убедитесь, что приложение имеет разрешение на публикацию продвигаемых уведомлений. Мы можем использовать метод canPostPromotedNotifications
класса NotificationManager
, чтобы проверить, имеет ли наше приложение действительный доступ.
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun checkInitialization(context: Context) { val canPostLiveUpdates = notificationManager.canPostPromotedNotifications() }
Перенаправьте пользователя в настройки для обновления его разрешений. Если результат последнего шага false
, мы можем перенаправить пользователя в настройки для обновления настроек, а затем продолжить.
val intent = Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT).setData( "package:${appContext.packageName}".toUri()), ) (context as Activity).startActivityForResult(intent, PERMISSION_REQUEST_CODE)
Проверьте, можно ли продвигать само уведомление. Мы можем использовать hasPromotableCharacteristics
из Notification
, чтобы убедиться, что уведомление подходит для оперативного обновления.
val isPromotable = notification.hasPromotableCharacteristics()
Пример Live Update для доставки еды
Давайте создадим канал уведомлений
object LiveUpdatesNotificationManager { private lateinit var notificationManager: NotificationManager private lateinit var appContext: Context const val CHANNEL_ID = "live_updates_16_channel_id" private const val CHANNEL_NAME = "live_updates_16_channel_name" private const val NOTIFICATION_ID = 4321 fun createChannel(context: Context, notifManager: NotificationManager) { notificationManager = notifManager val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, IMPORTANCE_DEFAULT) appContext = context notificationManager.createNotificationChannel(channel) }
Для нашего случая использования у нас будет следующие пять состояний:
- Заказ размещен или подтвержден
- Готовится
- В пути
- Прибывает
- Доставлен
Для начала давайте начнем с базового уведомления
fun buildBaseNotification(appContext: Context): Notification.Builder { return Notification.Builder(appContext, CHANNEL_ID) .setSmallIcon(R.drawable.ic_launcher_foreground) .setOngoing(true) .setColorized(true) .setColor(Color.GRAY) }
Нам нужно установить style
вProgressStyle
, который может обновляться в режиме реального времени.
Итак, давайте создадим Progress style
для каждого случая.
Используя базовое уведомление из предыдущего шага, мы будем развивать его.
Шаг 1 — Заказ размещен или подтвержден
fun buildBaseNotification(): Notification.Builder { return buildBaseNotification(appContext, INITIALIZING) .setContentTitle("You order is being placed") .setContentText("Confirming with Spicy7...") } @RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildBaseProgressStyle(): ProgressStyle { val progressStyle = ProgressStyle() .setProgressPoints( listOf( ProgressStyle.Point(25).setColor(Color.MAGENTA), ProgressStyle.Point(50).setColor(Color.RED), ProgressStyle.Point(75).setColor(Color.GREEN) ) ).setProgressSegments( listOf( ProgressStyle.Segment(25).setColor(Color.BLUE), ProgressStyle.Segment(25).setColor(Color.MAGENTA), ProgressStyle.Segment(25).setColor(Color.LTGRAY), ProgressStyle.Segment(25).setColor(Color.RED) ) ) return progressStyle }
Итак, мы начали с 3 точками и четырьмя сегментами.
Результат:
Шаг 2 — Заказ готовится
Мы обновляем прогресс до 25 и добавляем большой значок к существующему уведомлению.
Заголовок и текст обновлены:
.setContentTitle(“Your order is being prepared”) .setContentText(“Next step will be delivery”)
Мы сохраняем три точки и четыре сегмента.
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildNotification(): Notification.Builder { return buildBaseNotification(appContext, FOOD_PREPARATION) .setContentTitle("Your order is being prepared") .setContentText("Next step will be delivery") .setLargeIcon( IconCompat.createWithResource( appContext, R.drawable.ic_notif_large, ).toIcon(appContext), ) .setStyle(buildBaseProgressStyle().setProgress(25)) } @RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildBaseProgressStyle(): ProgressStyle { // same like step 1. }
Результат:
Шаг 3 — Заказ доставляется
Здесь мы устанавливаем прогресс на 50 и устанавливаем иконку доставки.
Заголовок и текст обновлены:
.setContentTitle(“Your order is on its way”) .setContentText(“Enroute to destination”)
Мы показываем один пункт (25) и четыре сегмента
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildNotification(): Notification.Builder { return buildBaseNotification(appContext, FOOD_ENROUTE) .setContentTitle("Your order is on its way") .setContentText("Enroute to destination") .setStyle( buildBaseProgressStyle() .setProgressTrackerIcon( IconCompat.createWithResource( appContext, R.drawable.shopping_bag, ).toIcon(appContext), ) .setProgress(50), ) .setLargeIcon( IconCompat.createWithResource( appContext, R.drawable.ic_notif_large, ).toIcon(appContext), ) } @RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildBaseProgressStyle(): ProgressStyle { val progressStyle = ProgressStyle() .setProgressPoints( listOf( ProgressStyle.Point(25).setColor(Color.MAGENTA) ) ).setProgressSegments( listOf( ProgressStyle.Segment(25).setColor(Color.BLUE), ProgressStyle.Segment(25).setColor(Color.MAGENTA), ProgressStyle.Segment(25).setColor(Color.LTGRAY), ProgressStyle.Segment(25).setColor(Color.RED) ) ) return progressStyle }
Результат:
Шаг 4 — Заказ прибывает
Здесь мы устанавливаем прогресс на 75 и устанавливаем иконку прибытия.
Заголовок и текст были обновлены:
.setContentTitle(“Your order is arriving...”) .setContentText(“Enjoy.”)
Мы показываем две точки (25, 50) и четыре сегмента.
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildNotification(): Notification.Builder { return buildBaseNotification(appContext, FOOD_ARRIVING) .setContentTitle("Your order is arriving...") .setContentText("Enjoy ") .setStyle( buildBaseProgressStyle(FOOD_ARRIVING) .setProgressTrackerIcon( IconCompat.createWithResource( appContext, R.drawable.local_shipping, ).toIcon(appContext), ) .setProgress(75), ) .setLargeIcon( IconCompat.createWithResource( appContext, R.drawable.ic_notif_large, ).toIcon(appContext), ) } @RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildBaseProgressStyle(): ProgressStyle { val progressStyle = ProgressStyle() .setProgressPoints( listOf( ProgressStyle.Point(25).setColor(Color.MAGENTA), ProgressStyle.Point(50).setColor(Color.RED), ) ).setProgressSegments( listOf( ProgressStyle.Segment(25).setColor(Color.BLUE), ProgressStyle.Segment(25).setColor(Color.MAGENTA), ProgressStyle.Segment(25).setColor(Color.LTGRAY), ProgressStyle.Segment(25).setColor(Color.RED) ) ) return progressStyle }
Результат:
Шаг 5 — Заказ доставлен
Здесь мы устанавливаем прогресс на 100 и новую иконку.
Заголовок и текст обновлены:
.setContentTitle(“Your order is complete.”) .setContentText(“Thank you for using our app.”)
Мы показываем три точки (25, 50, 75) и четыре сегмента.
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildNotification(): Notification.Builder { return buildBaseNotification(appContext, ORDER_COMPLETE) .setContentTitle("Your order is complete.") .setContentText("Thank you for using our app.") .setStyle( buildBaseProgressStyle(ORDER_COMPLETE) .setProgressTrackerIcon( IconCompat.createWithResource( appContext, R.drawable.check_box, ).toIcon(appContext), ) .setProgress(100), ) .setLargeIcon( IconCompat.createWithResource( appContext, R.drawable.ic_notif_large, ).toIcon(appContext), ) } @RequiresApi(Build.VERSION_CODES.BAKLAVA) fun buildBaseProgressStyle(): ProgressStyle { val progressStyle = ProgressStyle() .setProgressPoints( listOf( ProgressStyle.Point(25).setColor(Color.MAGENTA), ProgressStyle.Point(50).setColor(Color.RED), ProgressStyle.Point(75).setColor(Color.LTGRAY) ) ) return progressStyle }
Результат:
Несколько важных моментов:
- Точки в начале и конце не отображаются на индикаторе прогресса
DEFAULT_PROGRESS_MAX
равен 100MAX_PROGRESS_POINT_LIMIT
равен 4- Максимальное значение индикатора прогресса рассчитывается на основе сегментов
Ссылка на официальную документацию: https://developer.android.com/about/versions/16/features/progress-centric-notifications
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.22
-
Новости2 недели назад
Видео и подкасты о мобильной разработке 2025.24
-
Вовлечение пользователей4 недели назад
Небольшое изменение в интерфейсе Duolingo, которое меняет все
-
Маркетинг и монетизация4 недели назад
Институциональные покупки: понимание и обнаружение