创建通知

通知在你的应用未在使用时提供有关应用中事件的简短、及时信息。本文档介绍如何使用各种功能创建通知。有关通知在 Android 上如何显示的简介,请参阅 通知概述。有关使用通知的示例代码,请参阅 GitHub 上的 People 示例

此页面中的代码使用来自 AndroidX 库的 NotificationCompat API。这些 API 使你能够添加仅在更新版本的 Android 上可用的功能,同时仍能提供向后兼容性,直至 Android 9(API 级别 28)。但是,某些功能(例如内联回复操作)在早期版本上会导致无操作。

添加 AndroidX Core 库

尽管大多数使用 Android Studio 创建的项目都包含使用 NotificationCompat 所需的依赖项,但请验证你的模块级 build.gradle 文件是否包含以下依赖项

Groovy

dependencies {
    implementation "androidx.core:core:2.2.0"
}

Kotlin

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

创建基本通知

通知以最基本、最紧凑的形式(也称为折叠形式)显示图标、标题和少量文本内容。本节介绍如何创建一个用户可以点击以在你的应用中启动活动的通知。

图 1. 具有图标、标题和一些文本的通知。

有关通知每个部分的更多详细信息,请阅读有关 通知解剖

声明运行时权限

Android 13(API 级别 33)及更高版本支持从应用发布非豁免通知(包括前台服务 (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 及更高版本,请改为设置频道重要性,如下一节所示。

Kotlin

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

Java

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

NotificationCompat.Builder 构造函数要求你提供一个频道 ID。这是 Android 8.0(API 级别 26)及更高版本兼容性所必需的,但被早期版本忽略。

默认情况下,通知的文本内容将被截断以适合一行。你可以通过创建可展开通知来显示其他信息。

图 2. 可展开通知的折叠形式和展开形式。

如果你希望你的通知更长,你可以通过使用 setStyle() 添加样式模板来启用可展开通知。例如,以下代码创建了一个更大的文本区域

Kotlin

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)

Java

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 版本上的条件阻止

Kotlin

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

Java

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

以下代码片段显示如何创建一个基本意图,以便在用户点击通知时打开活动

Kotlin

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

Java

// 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(),当用户点击通知时,它会自动 删除通知

前面的示例中显示的 setFlags() 方法在用户使用通知打开你的应用后保留了用户的预期导航体验。你可能希望根据你正在启动的活动类型来使用它,它可以是以下其中之一

  • 专门用于响应通知的活动。用户没有理由在正常应用使用期间导航到此活动,因此活动启动新任务而不是添加到你的应用的现有 任务和后退栈 中。这是前面示例中创建的意图类型。

  • 存在于你的应用的常规应用流程中的活动。在这种情况下,启动活动会创建后退栈,以便保留用户对 后退和向上按钮 的预期。

有关配置通知意图的不同方法的更多信息,请参阅 从通知启动活动

显示通知

要使通知显示,请调用 NotificationManagerCompat.notify(),并将通知的唯一 ID 和 NotificationCompat.Builder.build() 的结果传递给它。这在以下示例中显示

Kotlin

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())
}

Java

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() 的通知 ID,因为在你想要 更新删除通知 时需要它。

此外,为了在运行 Android 13 及更高版本的设备上测试基本通知,请手动打开通知或创建对话框以请求通知。

添加操作按钮

通知最多可以提供三个操作按钮,让用户可以快速响应,例如延迟提醒或回复短信。但这些操作按钮不能重复用户 点击通知 时执行的操作。

图 3. 具有一个操作按钮的通知。

要添加操作按钮,请将 PendingIntent 传递给 addAction() 方法。这类似于设置通知的默认点击操作,不同之处在于,您可以执行其他操作,例如启动一个在后台执行作业的 BroadcastReceiver,以便操作不会中断已打开的应用程序。

例如,以下代码展示了如何向特定接收器发送广播

Kotlin

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)

Java

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 以运行后台作业的更多信息,请参阅 广播概述

如果您要构建一个带有媒体播放按钮的通知(例如暂停和跳过曲目),请参阅如何 创建带有媒体控制的通知

添加直接回复操作

直接回复操作是在 Android 7.0(API 级别 24)中引入的,它允许用户直接在通知中输入文本。然后,文本将在不打开活动的情况下传递到您的应用程序。例如,您可以使用直接回复操作让用户回复短信或从通知内更新任务列表。

图 4. 点击“回复”按钮将打开文本输入。

直接回复操作会以通知中的额外按钮形式显示,该按钮会打开文本输入。当用户完成输入时,系统会将文本回复附加到您为通知操作指定的意图,并将意图发送到您的应用程序。

添加回复按钮

要创建支持直接回复的通知操作,请按照以下步骤操作

  1. 创建一个 RemoteInput.Builder 实例,您可以将其添加到通知操作中。此类的构造函数接受一个字符串,系统会将其用作文本输入的键。您的应用程序稍后将使用该键来检索输入文本。

    Kotlin

      // 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()
      }
      

    Java

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

    Kotlin

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

    Java

      // Build a PendingIntent for the reply action to trigger.
      PendingIntent replyPendingIntent =
              PendingIntent.getBroadcast(getApplicationContext(),
                      conversation.getConversationId(),
                      getMessageReplyIntent(conversation.getConversationId()),
                      PendingIntent.FLAG_UPDATE_CURRENT);
      
  3. 使用 addRemoteInput()RemoteInput 对象附加到操作。

    Kotlin

      // 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()
      

    Java

      // 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. 将操作应用于通知并发出通知。

    Kotlin

      // 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)
      }
      

    Java

      // 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 所示。

从回复中检索用户输入

要从通知的回复 UI 中接收用户输入,请调用 RemoteInput.getResultsFromIntent(),并将 Intent 传递给 BroadcastReceiver

Kotlin

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

Java

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

处理完文本后,通过使用相同的 ID 和标签(如果使用)调用 NotificationManagerCompat.notify() 来更新通知。这对于隐藏直接回复 UI 并向用户确认已正确接收和处理他们的回复是必要的。

Kotlin

// 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)
}

Java

// 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 值重新发布通知,如下面的示例所示。

Kotlin

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())
}

Java

...
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_ALARMCATEGORY_REMINDERCATEGORY_EVENTCATEGORY_CALL),请通过将相应的类别传递给 setCategory() 来声明它。

Kotlin

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)

Java

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 中定义的类别之一匹配时才这样做。

显示紧急消息

您的应用程序可能需要显示紧急的、时间敏感的消息,例如来电或响铃的闹钟。在这些情况下,您可以将全屏意图与通知关联。

当调用通知时,用户会看到以下内容之一,具体取决于设备的锁定状态

  • 如果用户的设备已锁定,则会出现全屏活动,覆盖锁屏。
  • 如果用户的设备已解锁,则通知会以扩展形式显示,其中包含用于处理或取消通知的选项。

以下代码片段演示了如何将通知与全屏意图关联

Kotlin

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)

Java

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 时,您还可以提供通知内容的替代版本,以隐藏某些详细信息。例如,短信应用程序可能会显示一个通知,显示“您有 3 条新短信”,但会隐藏消息内容和发件人。要提供此替代通知,首先使用 NotificationCompat.Builder 创建替代通知,如往常一样。然后,使用 setPublicVersion() 将替代通知附加到普通通知。

请记住,用户始终对他们的通知是否在锁屏上可见拥有最终控制权,并且可以根据您的应用程序的通知频道对其进行控制。

更新通知

要在发出通知后更新通知,请再次调用 NotificationManagerCompat.notify(),并传递与之前相同的 ID。如果之前的通知已关闭,则会创建一个新的通知。

您可以选择调用 setOnlyAlertOnce(),以便通知仅在通知首次出现时中断用户(使用声音、振动或视觉线索),而不会在之后的更新中中断用户。

删除通知

通知会一直可见,直到发生以下情况之一

  • 用户关闭通知。
  • 用户点击通知(如果您在创建通知时调用了 setAutoCancel())。
  • 您对特定通知 ID 调用 cancel()。此方法还会删除正在进行的通知。
  • 您可以调用 cancelAll(),它会移除您之前发布的所有通知。
  • 如果您在创建通知时使用 setTimeoutAfter() 设置了超时时间,则指定的时间段会过去。如果需要,您可以在指定的时间段过去之前取消通知。

消息应用的最佳实践

在为您的消息和聊天应用创建通知时,请考虑此处列出的最佳实践。

使用 MessagingStyle

从 Android 7.0 (API 级别 24) 开始,Android 提供了一种专门用于消息内容的通知样式模板。使用 NotificationCompat.MessagingStyle 类,您可以更改通知上显示的几个标签,包括对话标题、附加消息和通知的内容视图。

以下代码片段演示了如何使用 MessagingStyle 类自定义通知的样式。

Kotlin

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

Java

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() 方法包含媒体消息,例如图像。支持模式为 image/* 的 MIME 类型。

使用直接回复

直接回复允许用户内联回复消息。

启用智能回复

  • 要启用智能回复,请在回复操作上调用 setAllowGeneratedResponses(true)。这会导致当通知桥接到 Wear OS 设备时,智能回复响应可供用户使用。智能回复响应由完全在手表上的机器学习模型使用 NotificationCompat.MessagingStyle 通知提供的上下文生成,不会将任何数据上传到互联网以生成响应。

添加通知元数据