在用户未使用您的应用时,通知可向他们及时提供有关应用事件的简短信息。本页面向您介绍如何针对 Android 4.0(API 级别 14)及更高版本创建具备各种功能的通知。有关通知如何在 Android 上显示的简介,请参阅通知概览。如需查看使用通知的示例代码,请参阅 Android 通知示例。
请注意,本页面上的代码使用了 Android 支持库中的
添加支持库
虽然使用 Android Studio 创建的大部分项目包含使用 build.gradle 文件是否包含以下依赖项:
dependencies {
implementation "com.android.support:support-compat:28.0.0"
}注意:com.android.support 组中的其他库也将 support-compat 包含为传递依赖项。因此,如果您已在使用其他支持库 API,您或许能够访问
创建基本通知
最基本、精简形式(也称为折叠形式)的通知会显示一个图标、一个标题和少量内容文本。在本部分中,您将了解如何创建用户点击后可启动应用中的 Activity 的通知。
图 1. 带有标题和文本的通知
如需详细了解通知的各个部分,请参阅通知剖析。
设置通知内容
首先,您需要使用
小图标,通过
通知优先级,通过
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);
请注意,
默认情况下,通知的文本内容会被截断以放在一行。如果您想要更长的通知,可以使用
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 及更高版本上提供通知。因此以下代码会被
Kotlin
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and 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 new and 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 及更高版本上发布任何通知,因此应在应用启动时立即执行这段代码。反复调用这段代码是安全的,因为创建现有通知渠道不会执行任何操作。
请注意,importance,它会使用
虽然必须按本文所示设置通知重要性/优先级,但系统不能保证您会获得提醒行为。在某些情况下,系统可能会根据其他因素更改重要性级别,并且用户始终可以重新定义指定渠道适用的重要性级别。
如需详细了解不同级别的含义,请参阅通知重要性级别。
设置通知的点按操作
每个通知都应该对点按操作做出响应,通常是在应用中打开对应于该通知的 Activity。为此,您必须指定通过
以下代码段展示了如何创建基本 Intent,以在用户点按通知时打开 Activity:
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, 0)
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 will fire 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, 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)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);
请注意,此代码会调用 移除通知。
以上所示的
专用于响应通知的 Activity。用户在正常使用应用时不会无缘无故想导航到这个 Activity,因此该 Activity 会启动一个新任务,而不是添加到应用的现有任务和返回堆栈。这就是以上示例中创建的 Intent 类型。
应用的常规应用流程中存在的 Activity。在这种情况下,启动 Activity 时应创建返回堆栈,以便保留用户对返回和向上按钮的预期。
如需详细了解配置通知 Intent 的不同方法,请参阅从通知启动 Activity。
显示通知
Kotlin
with(NotificationManagerCompat.from(this)) {
// notificationId is a unique int for each notification that you must define
notify(notificationId, builder.build())
}Java
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, builder.build());
注意:从 Android 8.1(API 级别 27)开始,应用每秒最多只能发出一次通知提示音。如果应用在一秒内发出了多条通知,这些通知都会按预期显示,但是每秒中只有第一条通知发出提示音。
添加操作按钮
一个通知最多可以提供三个操作按钮,让用户能够快速响应,例如暂停提醒,甚至回复短信。但这些操作按钮不应该重复用户在点按通知时执行的操作。
图 2. 带有一个操作按钮的通知
如需添加操作按钮,请将
例如,以下代码演示了如何向特定接收者发送广播:
Kotlin
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
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);
如需详细了解如何构建 广播指南。
如果您尝试构建包含媒体播放按钮(例如暂停和跳过曲目)的通知,请参阅如何创建包含媒体控件的通知。
注意:在 Android 10(API 级别 29)和更高版本中,如果应用不提供自己的通知操作按钮,则平台会自动生成通知操作按钮。如果您不希望应用通知显示任何建议的回复或操作,可以使用
添加直接回复操作
Android 7.0(API 级别 24)中引入的直接回复操作允许用户直接在通知中输入文本,然后会直接提交给应用,而不必打开 Activity。例如,您可以使用直接回复操作让用户从通知内回复短信或更新任务列表。
图 3. 点按“回复”按钮会打开文本输入框
直接回复操作在通知中显示为一个额外按钮,可打开文本输入。当用户完成输入后,系统会将文本回复附加到您为通知操作指定的 Intent,然后将 Intent 发送到您的应用。
添加回复按钮
如需创建支持直接回复的通知操作,请按照如下所述操作:
创建一个可添加到通知操作的
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();
为回复操作创建
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);
注意:如果重复使用 true 的 Intent。会话 ID 会作为 Intent 的 extra 包的一部分被频繁传递,但调用
使用
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();
对通知应用操作并发出通知。
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);
当用户触发通知操作时,系统会提示用户输入回复,如图 3 所示。
从回复中检索用户输入
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 和标记(如果使用)调用
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);
在处理这个新通知时,请使用传递给接收者的
您还应通过调用 消息式通知,并在会话中附加新消息。
如需了解有关即时通讯应用通知的更多建议,请参阅有关即时通讯应用的最佳做法。
添加进度条
通知可以包含动画形式的进度指示器,向用户显示正在进行的操作的状态。
图 4. 操作期间和操作结束后的进度条。
如果您可以估算操作在任何时间点的完成进度,应通过调用
随着操作的继续,持续使用 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 here that tracks the progress.
// Usually, this should be 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 one more time 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 here that tracks the progress.
// Usually, this should be 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 one more time to remove the progress bar
builder.setContentText("Download complete")
.setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());
操作结束时,progress 应该等于 max。您可以在操作完成后仍显示进度条,也可以将其移除。无论哪种情况,都请记得更新通知文本,显示操作已完成。如需移除进度条,请调用
注意:由于进度条要求应用持续更新通知,因此该代码通常应在后台服务中运行。
如需显示不确定性进度条(不指示完成百分比的进度条),请调用
同时,请记得更改通知文本,表明操作已完成。
注意:如果您实际需要下载一个文件,应考虑使用
设置系统范围的类别
Android 使用一些预定义的系统范围类别来确定在用户启用勿扰模式后是否发出指定通知来干扰客户。
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);
系统使用这些关于通知类别的信息来决定当设备处于勿扰模式时是否显示通知。
但是,设置系统范围类别并不是必需操作,仅在通知符合
显示紧急消息
您的应用可能需要显示紧急的时效性消息,例如来电或响铃警报。在这些情况下,您可以将全屏 Intent 与通知关联。调用通知时,根据设备的锁定状态,用户会看到以下情况之一:
如果用户设备被锁定,会显示全屏 Activity,覆盖锁屏。
如果用户设备处于解锁状态,通知以展开形式显示,其中包含用于处理或关闭通知的选项。
注意:包含全屏 Intent 的通知有很强的干扰性,因此这类通知只能用于最紧急的时效性消息。注意:如果应用的目标平台是 Android 10(API 级别 29)或更高版本,必须在应用清单文件中请求 USE_FULL_SCREEN_INTENT 权限,以便系统启动与时效性通知关联的全屏 Activity。
以下代码段展示了如何将通知与全屏 Intent 关联:
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);
设置锁定屏幕公开范围
如需控制锁定屏幕中通知的可见详情级别,请调用
当设置 如需提供此备用通知,首先请像平时一样使用
但是,对于通知在锁定屏幕上是否可见,用户始终拥有最终控制权,甚至可以根据应用的通知渠道来控制公开范围。
更新通知
如需在发出此通知后对其进行更新,请再次调用
您可以选择性调用
注意:Android 会在更新通知时应用速率限制。如果您过于频繁地发布对某条通知的更新(不到一秒内发布多条通知),系统可能会丢弃部分更新。
移除通知
除非发生以下情况之一,否则通知仍然可见:
用户关闭通知。
用户点击通知,且您在创建通知时调用了
您针对特定的通知 ID 调用了
您调用了
如果您在创建通知时使用
有关即时通讯应用的最佳做法
使用下文所列的最佳做法作为快速参考,了解在为消息和聊天应用创建通知时应注意哪些要点。
使用 MessagingStyle
从 Android 7.0(API 级别 24)起,Android 提供了专用于消息内容的通知样式模板。使用
以下代码段展示了如何使用 MessagingStyle 类自定义通知的样式。
Kotlin
var notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setStyle(NotificationCompat.MessagingStyle("Me")
.setConversationTitle("Team lunch")
.addMessage("Hi", timestamp1, null) // Pass in null for user.
.addMessage("What's up?", timestamp2, "Coworker")
.addMessage("Not much", timestamp3, null)
.addMessage("How about lunch?", timestamp4, "Coworker"))
.build()Java
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setStyle(new NotificationCompat.MessagingStyle("Me")
.setConversationTitle("Team lunch")
.addMessage("Hi", timestamp1, null) // Pass in null for user.
.addMessage("What's up?", timestamp2, "Coworker")
.addMessage("Not much", timestamp3, null)
.addMessage("How about lunch?", timestamp4, "Coworker"))
.build();
从 Android 8.0(API 级别 26)起,使用
调用
使用
使用直接回复
直接回复允许用户以内嵌方式回复消息。
在用户通过内嵌回复操作回复后,使用 MessagingStyle 通知,并且不要撤消或取消通知。不取消通知可以让用户从通知发送多个回复。
通过向通知添加历史消息,使用 addHistoricMessage() 方法向直接回复会话提供上下文。
启用智能回复
如需启用智能回复,请对回复操作调用 setAllowGeneratedResponses(true)。这样,在通知桥接到 Wear OS 设备后,用户就能使用智能回复响应。智能回复响应由一个完全在手表上的机器学习模型使用
添加通知元数据