Создать уведомление

Уведомления предоставляют краткую своевременную информацию о событиях в вашем приложении, пока оно не используется. В этом документе показано, как создать уведомление с различными функциями. Для ознакомления с тем, как уведомления отображаются на Android, см. Обзор уведомлений . Для примера кода, который использует уведомления, см. пример SociaLite на GitHub.

Код на этой странице использует API NotificationCompat из библиотеки AndroidX. Эти API позволяют добавлять функции, доступные только в новых версиях Android, при этом обеспечивая совместимость с Android 9 (уровень API 28). Однако некоторые функции, такие как встроенное действие ответа, приводят к отсутствию операции в более ранних версиях.

Добавьте библиотеку AndroidX Core

Хотя большинство проектов, созданных с помощью Android Studio, включают необходимые зависимости для использования NotificationCompat , убедитесь, что файл build.gradle на уровне модуля включает следующую зависимость:

Круто

dependencies {
    implementation "androidx.core:core-ktx:1.16.0"
}

Котлин

dependencies {
    implementation("androidx.core:core-ktx:1.16.0")
}

Создать базовое уведомление

Уведомление в своей самой базовой и компактной форме — также известной как свернутая форма — отображает значок, заголовок и небольшое количество текстового контента. В этом разделе показано, как создать уведомление, которое пользователь может нажать, чтобы запустить действие в вашем приложении.

Рисунок 1. Уведомление со значком, заголовком и текстом.

Более подробную информацию о каждой части уведомления можно найти в статье об анатомии уведомления .

Объявите разрешение на выполнение

Android 13 (уровень API 33) и выше поддерживает разрешение времени выполнения для публикации неисключенных (включая Foreground Services (FGS)) уведомлений из приложения.

Разрешение, которое вам необходимо объявить в файле манифеста вашего приложения, представлено в следующем фрагменте кода:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

Более подробную информацию о разрешениях времени выполнения см. в разделе Разрешение времени выполнения уведомлений .

Установить содержание уведомления

Чтобы начать, установите содержимое и канал уведомления с помощью объекта NotificationCompat.Builder . В следующем примере показано, как создать уведомление со следующим:

  • Маленькая иконка, устанавливаемая setSmallIcon() . Это единственный видимый пользователю контент, который требуется.

  • Заголовок, устанавливаемый с помощью setContentTitle() .

  • Основной текст, установленный с помощью setContentText() .

  • Приоритет уведомления, установленный setPriority() . Приоритет определяет, насколько навязчивым будет уведомление на Android 7.1 и более ранних версиях. Для Android 8.0 и более поздних версий вместо этого установите важность канала, как показано в следующем разделе.

Котлин

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Ява

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Конструктор NotificationCompat.Builder требует указать идентификатор канала. Это необходимо для совместимости с Android 8.0 (уровень API 26) и более поздними версиями, но игнорируется более ранними версиями.

По умолчанию текстовое содержимое уведомления обрезается до одной строки. Вы можете отобразить дополнительную информацию, создав расширяемое уведомление.

Рисунок 2. Расширяемое уведомление в свернутом и развернутом виде.

Если вы хотите, чтобы ваше уведомление было длиннее, вы можете включить расширяемое уведомление, добавив шаблон стиля с помощью setStyle() . Например, следующий код создает большую текстовую область:

Котлин

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Ява

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Дополнительную информацию о других стилях больших уведомлений, включая добавление изображения и элементов управления воспроизведением мультимедиа, см. в разделе Создание расширяемого уведомления .

Создайте канал и установите важность

Прежде чем вы сможете доставить уведомление на Android 8.0 и более поздних версиях, зарегистрируйте канал уведомлений вашего приложения в системе, передав экземпляр NotificationChannel в createNotificationChannel() . Следующий код блокируется условием в версии SDK_INT :

Котлин

private fun createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.channel_name)
        val descriptionText = getString(R.string.channel_description)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            description = descriptionText
        }
        // Register the channel with the system.
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

Ява

private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = getString(R.string.channel_name);
        String description = getString(R.string.channel_description);
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this.
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
}

Поскольку вы должны создать канал уведомлений перед публикацией любых уведомлений на Android 8.0 и более поздних версиях, выполните этот код сразу после запуска приложения. Можно безопасно вызывать его повторно, поскольку создание существующего канала уведомлений не выполняет никаких операций.

Конструктор NotificationChannel требует importance , используя одну из констант из класса NotificationManager . Этот параметр определяет, как прерывать пользователя для любого уведомления, принадлежащего этому каналу. Установите приоритет с помощью setPriority() для поддержки Android 7.1 и более ранних версий, как показано в предыдущем примере.

Хотя вы должны установить важность или приоритет уведомления, как показано в следующем примере, система не гарантирует поведение оповещения, которое вы получите. В некоторых случаях система может изменить уровень важности на основе других факторов, и пользователь всегда может переопределить, какой уровень важности будет для данного канала.

Более подробную информацию о том, что означают различные уровни, можно найти в статье об уровнях важности уведомлений .

Установите действие при нажатии уведомления

Каждое уведомление должно реагировать на нажатие, обычно для открытия активности в вашем приложении, которая соответствует уведомлению. Для этого укажите намерение содержимого, определенное с помощью объекта PendingIntent , и передайте его в setContentIntent() .

В следующем фрагменте показано, как создать базовое намерение для открытия действия, когда пользователь нажимает на уведомление:

Котлин

// Create an explicit intent for an Activity in your app.
val intent = Intent(this, AlertDetails::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

Ява

// Create an explicit intent for an Activity in your app.
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true);

Этот код вызывает setAutoCancel() , который автоматически удаляет уведомление, когда пользователь нажимает на него.

Флаги намерений в предыдущем примере сохраняют ожидаемый опыт навигации пользователя после того, как пользователь открывает ваше приложение с помощью уведомления. Вы можете захотеть использовать его в зависимости от типа активности, которую вы начинаете, которая может быть одной из следующих:

  • Активность, которая существует исключительно для ответов на уведомление. Нет причин, по которым пользователь переходит к этой активности во время обычного использования приложения, поэтому активность запускает новую задачу вместо того, чтобы быть добавленной к существующей задаче вашего приложения и back stack . Это тип намерения, созданного в предыдущем примере.

  • Активность, которая существует в обычном потоке приложения вашего приложения. В этом случае запуск активности создает стек возврата, чтобы ожидания пользователя относительно кнопок «Назад» и «Вверх» сохранялись.

Дополнительную информацию о различных способах настройки цели уведомления см. в разделе Запуск действия из уведомления .

Показать уведомление

Чтобы уведомление появилось, вызовите NotificationManagerCompat.notify() , передав ему уникальный идентификатор уведомления и результат NotificationCompat.Builder.build() . Это показано в следующем примере:

Котлин

with(NotificationManagerCompat.from(this)) {
    if (ActivityCompat.checkSelfPermission(
            this@MainActivity,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        // ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
        //                                        grantResults: IntArray)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.

        return@with
    }
    // notificationId is a unique int for each notification that you must define.
    notify(NOTIFICATION_ID, builder.build())
}

Ява

with(NotificationManagerCompat.from(this)) {
   if (ActivityCompat.checkSelfPermission(
           this@MainActivity,
           Manifest.permission.POST_NOTIFICATIONS
       ) != PackageManager.PERMISSION_GRANTED
   ) {
       // TODO: Consider calling
       // ActivityCompat#requestPermissions
       // here to request the missing permissions, and then overriding
       // public void onRequestPermissionsResult(int requestCode, String[] permissions,
       //                                        int[] grantResults)
       // to handle the case where the user grants the permission. See the documentation
       // for ActivityCompat#requestPermissions for more details.

       return
   }
   // notificationId is a unique int for each notification that you must define.
   notify(NOTIFICATION_ID, builder.build())
}

Сохраните идентификатор уведомления, который вы передаете в NotificationManagerCompat.notify() , так как он вам понадобится, когда вы захотите обновить или удалить уведомление .

Кроме того, чтобы протестировать базовые уведомления на устройствах под управлением Android 13 и выше, включите уведомления вручную или создайте диалоговое окно для запроса уведомлений.

Добавить кнопки действий

Уведомление может предлагать до трех кнопок действий, которые позволяют пользователю быстро реагировать, например, отложить напоминание или ответить на текстовое сообщение. Но эти кнопки действий не должны дублировать действие, выполняемое при нажатии пользователем уведомления .

Рисунок 3. Уведомление с одной кнопкой действия.

Чтобы добавить кнопку действия, передайте PendingIntent в метод addAction() . Это похоже на настройку действия нажатия по умолчанию для уведомления, за исключением того, что вместо запуска действия вы можете сделать что-то другое, например запустить BroadcastReceiver , который выполняет работу в фоновом режиме, чтобы действие не прерывало уже открытое приложение.

Например, следующий код показывает, как отправить широковещательную передачу определенному получателю:

Котлин

val ACTION_SNOOZE = "snooze"

val snoozeIntent = Intent(this, MyBroadcastReceiver::class.java).apply {
    action = ACTION_SNOOZE
    putExtra(EXTRA_NOTIFICATION_ID, 0)
}
val snoozePendingIntent: PendingIntent =
    PendingIntent.getBroadcast(this, 0, snoozeIntent, 0)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent)

Ява

String ACTION_SNOOZE = "snooze"

Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(ACTION_SNOOZE);
snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0);
PendingIntent snoozePendingIntent =
        PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent);

Дополнительную информацию о создании BroadcastReceiver для выполнения фоновой работы см. в обзоре Broadcasts .

Если вместо этого вы пытаетесь создать уведомление с кнопками воспроизведения мультимедиа, например, для приостановки и пропуска треков, узнайте, как создать уведомление с элементами управления мультимедиа .

Добавить действие прямого ответа

Действие прямого ответа, представленное в Android 7.0 (уровень API 24), позволяет пользователям вводить текст непосредственно в уведомление. Затем текст доставляется в ваше приложение без открытия действия. Например, вы можете использовать действие прямого ответа, чтобы позволить пользователям отвечать на текстовые сообщения или обновлять списки задач из уведомления.

Рисунок 4. Нажатие кнопки «Ответить» открывает поле для ввода текста.

Действие прямого ответа отображается как дополнительная кнопка в уведомлении, которая открывает текстовый ввод. Когда пользователь заканчивает печатать, система прикрепляет текстовый ответ к намерению, которое вы указываете для действия уведомления, и отправляет намерение в ваше приложение.

Добавить кнопку ответа

Чтобы создать действие уведомления, поддерживающее прямой ответ, выполните следующие действия:

  1. Создайте экземпляр RemoteInput.Builder , который можно добавить в действие уведомления. Конструктор этого класса принимает строку, которую система использует в качестве ключа для ввода текста. Ваше приложение позже использует этот ключ для извлечения текста ввода.

    Котлин

      // Key for the string that's delivered in the action's intent.
      private val KEY_TEXT_REPLY = "key_text_reply"
      var replyLabel: String = resources.getString(R.string.reply_label)
      var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
          setLabel(replyLabel)
          build()
      }
      

    Ява

      // Key for the string that's delivered in the action's intent.
      private static final String KEY_TEXT_REPLY = "key_text_reply";
    
      String replyLabel = getResources().getString(R.string.reply_label);
      RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
              .setLabel(replyLabel)
              .build();
      
  2. Создайте PendingIntent для действия ответа.

    Котлин

      // Build a PendingIntent for the reply action to trigger.
      var replyPendingIntent: PendingIntent =
          PendingIntent.getBroadcast(applicationContext,
              conversation.getConversationId(),
              getMessageReplyIntent(conversation.getConversationId()),
              PendingIntent.FLAG_UPDATE_CURRENT)
      

    Ява

      // Build a PendingIntent for the reply action to trigger.
      PendingIntent replyPendingIntent =
              PendingIntent.getBroadcast(getApplicationContext(),
                      conversation.getConversationId(),
                      getMessageReplyIntent(conversation.getConversationId()),
                      PendingIntent.FLAG_UPDATE_CURRENT);
      
  3. Присоедините объект RemoteInput к действию с помощью addRemoteInput() .

    Котлин

      // Create the reply action and add the remote input.
      var action: NotificationCompat.Action =
          NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
              getString(R.string.label), replyPendingIntent)
              .addRemoteInput(remoteInput)
              .build()
      

    Ява

      // Create the reply action and add the remote input.
      NotificationCompat.Action action =
              new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
                      getString(R.string.label), replyPendingIntent)
                      .addRemoteInput(remoteInput)
                      .build();
      
  4. Примените действие к уведомлению и отправьте уведомление.

    Котлин

      // Build the notification and add the action.
      val newMessageNotification = Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build()
    
      // Issue the notification.
      with(NotificationManagerCompat.from(this)) {
          notificationManager.notify(notificationId, newMessageNotification)
      }
      

    Ява

      // Build the notification and add the action.
      Notification newMessageNotification = new Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build();
    
      // Issue the notification.
      NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
      notificationManager.notify(notificationId, newMessageNotification);
      

Система предлагает пользователю ввести ответ при запуске действия уведомления, как показано на рисунке 4.

Извлечь пользовательский ввод из ответа

Чтобы получить пользовательский ввод из пользовательского интерфейса ответа на уведомление, вызовите RemoteInput.getResultsFromIntent() , передав ему Intent , полученный вашим BroadcastReceiver :

Котлин

private fun getMessageText(intent: Intent): CharSequence? {
    return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY)
}

Ява

private CharSequence getMessageText(Intent intent) {
    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
    if (remoteInput != null) {
        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
    }
    return null;
 }

После обработки текста обновите уведомление, вызвав NotificationManagerCompat.notify() с тем же идентификатором и тегом, если он используется. Это необходимо, чтобы скрыть пользовательский интерфейс прямого ответа и подтвердить пользователю, что его ответ получен и обработан правильно.

Котлин

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
val repliedNotification = Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build()

// Issue the new notification.
NotificationManagerCompat.from(this).apply {
    notificationManager.notify(notificationId, repliedNotification)
}

Ява

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
Notification repliedNotification = new Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build();

// Issue the new notification.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, repliedNotification);

При работе с этим новым уведомлением используйте контекст, переданный методу onReceive() получателя.

Добавьте ответ в конец уведомления, вызвав setRemoteInputHistory() . Однако, если вы создаете приложение для обмена сообщениями, создайте уведомление в стиле обмена сообщениями и добавьте новое сообщение в беседу.

Дополнительные рекомендации по уведомлениям от приложений для обмена сообщениями см. в разделе о рекомендациях по использованию приложений для обмена сообщениями .

Добавить индикатор выполнения

Уведомления могут включать анимированный индикатор хода выполнения, показывающий пользователям статус текущей операции.

Рисунок 5. Индикатор выполнения операции.

Если вы можете оценить, какая часть операции завершена в любой момент времени, используйте «определенную» форму индикатора, как показано на рисунке 5, вызвав setProgress(max, progress, false) . Первый параметр — это то, что является «полным» значением, например 100. Второй — это то, какая часть завершена. Последний указывает, что это определенный индикатор выполнения.

По мере выполнения операции постоянно вызывайте setProgress(max, progress, false) с обновленным значением progress и повторно отправляйте уведомление, как показано в следующем примере.

Котлин

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentTitle("Picture Download")
    setContentText("Download in progress")
    setSmallIcon(R.drawable.ic_notification)
    setPriority(NotificationCompat.PRIORITY_LOW)
}
val PROGRESS_MAX = 100
val PROGRESS_CURRENT = 0
NotificationManagerCompat.from(this).apply {
    // Issue the initial notification with zero progress.
    builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
    notify(notificationId, builder.build())

    // Do the job that tracks the progress here.
    // Usually, this is in a worker thread.
    // To show progress, update PROGRESS_CURRENT and update the notification with:
    // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
    // notificationManager.notify(notificationId, builder.build());

    // When done, update the notification once more to remove the progress bar.
    builder.setContentText("Download complete")
            .setProgress(0, 0, false)
    notify(notificationId, builder.build())
}

Ява

...
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentTitle("Picture Download")
        .setContentText("Download in progress")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW);

// Issue the initial notification with zero progress.
int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
notificationManager.notify(notificationId, builder.build());

// Do the job that tracks the progress here.
// Usually, this is in a worker thread.
// To show progress, update PROGRESS_CURRENT and update the notification with:
// builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
// notificationManager.notify(notificationId, builder.build());

// When done, update the notification once more to remove the progress bar.
builder.setContentText("Download complete")
        .setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());

В конце операции progress должен быть равен max . Вы можете оставить индикатор выполнения, чтобы показать, что операция выполнена, или удалить его. В любом случае обновите текст уведомления, чтобы показать, что операция выполнена. Чтобы удалить индикатор выполнения, вызовите setProgress(0, 0, false) .

Чтобы отобразить неопределенный индикатор выполнения (индикатор, который не показывает процент выполнения), вызовите setProgress(0, 0, true) . Результатом будет индикатор, который имеет тот же стиль, что и предыдущий индикатор выполнения, за исключением того, что это непрерывная анимация, которая не показывает завершение. Анимация выполнения будет работать до тех пор, пока вы не вызовете setProgress(0, 0, false) и не обновите уведомление, чтобы удалить индикатор активности.

Не забудьте изменить текст уведомления, чтобы указать, что операция завершена.

Установить общесистемную категорию

Android использует предопределенные общесистемные категории, чтобы определить, следует ли беспокоить пользователя определенным уведомлением, когда пользователь включает режим «Не беспокоить» .

Если ваше уведомление попадает в одну из категорий уведомлений, определенных в NotificationCompat , например CATEGORY_ALARM , CATEGORY_REMINDER , CATEGORY_EVENT или CATEGORY_CALL , объявите его таковым, передав соответствующую категорию в setCategory() :

Котлин

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE)

Ява

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE);

Система использует эту информацию о вашей категории уведомлений для принятия решений об отображении вашего уведомления, когда устройство находится в режиме «Не беспокоить». Однако вам не обязательно устанавливать общесистемную категорию. Делайте это только в том случае, если ваши уведомления соответствуют одной из категорий, определенных в NotificationCompat .

Показать срочное сообщение

Вашему приложению может потребоваться отобразить срочное, чувствительное ко времени сообщение, например, входящий телефонный звонок или звонок будильника. В таких ситуациях вы можете связать полноэкранное намерение с вашим уведомлением.

При вызове уведомления пользователи видят одно из следующих сообщений в зависимости от статуса блокировки устройства:

  • Если устройство пользователя заблокировано, появляется полноэкранное действие, закрывающее экран блокировки.
  • Если устройство пользователя разблокировано, уведомление отображается в развернутом виде, включающем варианты обработки или отклонения уведомления.

Следующий фрагмент кода демонстрирует, как связать уведомление с полноэкранным намерением:

Котлин

val fullScreenIntent = Intent(this, ImportantActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
    fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true)

Ява

Intent fullScreenIntent = new Intent(this, ImportantActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true);

Установить видимость экрана блокировки

Чтобы контролировать уровень детализации, отображаемый в уведомлении на экране блокировки, вызовите setVisibility() и укажите одно из следующих значений:

  • VISIBILITY_PUBLIC : полное содержимое уведомления отображается на экране блокировки.

  • VISIBILITY_SECRET : никакая часть уведомления не отображается на экране блокировки.

  • VISIBILITY_PRIVATE : на экране блокировки отображается только основная информация, такая как значок уведомления и заголовок содержимого. Полное содержимое уведомления не отображается.

При установке VISIBILITY_PRIVATE вы также можете предоставить альтернативную версию содержимого уведомления, которая скрывает определенные детали. Например, приложение SMS может отображать уведомление, которое показывает «У вас 3 новых текстовых сообщения», но скрывает содержимое сообщения и отправителей. Чтобы предоставить это альтернативное уведомление, сначала создайте альтернативное уведомление с помощью NotificationCompat.Builder , как обычно. Затем прикрепите альтернативное уведомление к обычному уведомлению с помощью setPublicVersion() .

Помните, что пользователь всегда имеет полный контроль над тем, будут ли его уведомления видны на экране блокировки, и может управлять ими с помощью каналов уведомлений вашего приложения.

Обновить уведомление

Чтобы обновить уведомление после его отправки, вызовите NotificationManagerCompat.notify() снова, передав ему тот же идентификатор, который вы использовали ранее. Если предыдущее уведомление отклонено, вместо него создается новое уведомление.

При желании вы можете вызвать setOnlyAlertOnce() , чтобы ваше уведомление прерывало пользователя — звуком, вибрацией или визуальными подсказками — только при первом появлении уведомления, а не при последующих обновлениях.

Удалить уведомление

Уведомления остаются видимыми до тех пор, пока не произойдет одно из следующих событий:

  • Пользователь отклоняет уведомление.
  • Пользователь нажимает на уведомление, если вы вызываете setAutoCancel() при создании уведомления.
  • Вы вызываете cancel() для определенного идентификатора уведомления. Этот метод также удаляет текущие уведомления.
  • Вы вызываете cancelAll() , который удаляет все ранее отправленные вами уведомления.
  • Указанная длительность истекает, если вы установили тайм-аут при создании уведомления с помощью setTimeoutAfter() . При необходимости вы можете отменить уведомление до истечения указанной длительности тайм-аута.

Лучшие практики для приложений обмена сообщениями

При создании уведомлений для приложений обмена сообщениями и чатов учитывайте перечисленные здесь рекомендации.

Использовать стиль сообщений

Начиная с Android 7.0 (уровень API 24), Android предоставляет шаблон стиля уведомления специально для содержимого сообщений. Используя класс NotificationCompat.MessagingStyle , вы можете изменить несколько меток, отображаемых в уведомлении, включая заголовок беседы, дополнительные сообщения и вид содержимого для уведомления.

В следующем фрагменте кода показано, как настроить стиль уведомления с помощью класса MessagingStyle .

Котлин

val user = Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build()

val notification = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with $sender")
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build()

Ява

Person user = new Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build();

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with " + sender)
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(new NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build();

Начиная с Android 9.0 (уровень API 28), также требуется использовать класс Person для оптимальной визуализации уведомления и его аватаров.

При использовании NotificationCompat.MessagingStyle выполните следующие действия:

  • Вызовите MessagingStyle.setConversationTitle() , чтобы задать заголовок для групповых чатов с более чем двумя людьми. Хорошим заголовком беседы может быть название группового чата или, если у него нет названия, список участников беседы. Без этого сообщение может быть ошибочно принято за принадлежность к индивидуальной беседе с отправителем самого последнего сообщения в беседе.
  • Используйте метод MessagingStyle.setData() для включения медиа-сообщений, таких как изображения. Поддерживаются типы MIME шаблона image/*.

Использовать прямой ответ

Функция прямого ответа позволяет пользователю отвечать непосредственно на сообщение.

  • После того, как пользователь ответит с помощью встроенного действия ответа, используйте MessagingStyle.addMessage() для обновления уведомления MessagingStyle и не отзывайте и не отменяйте уведомление. Не отменяя уведомление, пользователь может отправлять несколько ответов из уведомления.
  • Чтобы сделать действие встроенного ответа совместимым с Wear OS, вызовите Action.WearableExtender.setHintDisplayInlineAction(true) .
  • Используйте метод addHistoricMessage() , чтобы предоставить контекст для прямого ответа, добавив исторические сообщения в уведомление.

Включить умный ответ

  • Чтобы включить Smart Reply, вызовите setAllowGeneratedResponses(true) в действии ответа. Это делает ответы Smart Reply доступными для пользователей, когда уведомление перенаправляется на устройство Wear OS. Ответы Smart Reply генерируются полностью на часах с помощью модели машинного обучения, используя контекст, предоставленный уведомлением NotificationCompat.MessagingStyle , и никакие данные не загружаются в Интернет для генерации ответов.

Добавить метаданные уведомления

  • Назначьте метаданные уведомления, чтобы сообщить системе, как обрабатывать уведомления вашего приложения, когда устройство находится в Do Not Disturb mode . Например, используйте метод addPerson() или setCategory(Notification.CATEGORY_MESSAGE) , чтобы переопределить режим «Не беспокоить».