Android各個版本上的通知Notification-創(chuàng)建不同樣式的通知

九、創(chuàng)建不同樣式的通知

1扒接、創(chuàng)建基本樣式的通知

a.基本通知

最基本、最緊湊的形式(也稱為“折疊形式”)的通知會顯示一個圖標(biāo)威鹿、標(biāo)題和少量文本內(nèi)容。


基本通知-包含圖標(biāo)轨香、標(biāo)題和一些文本的通知
設(shè)置通知的內(nèi)容

使用 NotificationCompat.Builder 對象設(shè)置通知的內(nèi)容和渠道忽你。

  • 小圖標(biāo),通過 setSmallIcon() 設(shè)置臂容。這是所必需的唯一用戶可見內(nèi)容科雳。

  • 標(biāo)題根蟹,通過 setContentTitle() 設(shè)置。

  • 正文文本炸渡,通過 setContentText() 設(shè)置娜亿。

  • 通知優(yōu)先級,通過 setPriority() 設(shè)置蚌堵。優(yōu)先級決定了 Android 7.1 及更低版本上的通知的干擾程度。對于 Android 8.0 及更高版本沛婴,請改為設(shè)置渠道重要性吼畏,如下一部分所示。

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

NotificationCompat.Builder 構(gòu)造函數(shù)要求您提供渠道 ID嘁灯。這是與 Android 8.0(API 級別 26)及更高版本兼容所必需的泻蚊,但被早期版本忽略。

創(chuàng)建渠道并設(shè)置重要性

需要先將 NotificationChannel 的實例傳遞給 createNotificationChannel()丑婿,在系統(tǒng)中注冊應(yīng)用的通知渠道性雄,然后才能在 Android 8.0 及更高版本上發(fā)送通知。

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

必須先創(chuàng)建通知渠道羹奉,然后才能在 Android 8.0 及更高版本上發(fā)布任何通知秒旋,因此請在應(yīng)用啟動時立即執(zhí)行此代碼。您可以放心地重復(fù)調(diào)用此方法诀拭,因為創(chuàng)建現(xiàn)有通知渠道不會執(zhí)行任何操作迁筛。

NotificationChannel 構(gòu)造函數(shù)需要 importance,它使用 NotificationManager 類中的一個常量耕挨。此參數(shù)確定對于屬于此渠道的任何通知细卧,如何干擾用戶。將優(yōu)先級設(shè)置為 setPriority() 以支持 Android 7.1 及更低版本筒占。
必須設(shè)置通知的重要性或優(yōu)先級贪庙,如以下示例所示,但系統(tǒng)不保證您會獲得提醒行為翰苫。在某些情況下止邮,系統(tǒng)可能會根據(jù)其他因素更改重要性級別,并且用戶可以隨時重新定義給定渠道的重要性級別革骨。

設(shè)置通知的點按操作

每個通知都必須響應(yīng)點按操作农尖,通常是為了打開應(yīng)用中與通知對應(yīng)的 activity。為此良哲,請指定使用 PendingIntent 對象定義的內(nèi)容 intent盛卡,并將其傳遞給 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)

此代碼會調(diào)用 setAutoCancel()筑凫,它會在用戶點按通知時自動移除通知滑沧。

上例中顯示的 setFlags() 方法在用戶使用通知打開您的應(yīng)用后保留了預(yù)期的導(dǎo)航體驗并村。您可能需要根據(jù)要啟動的 activity 類型(可以是以下類型之一)來使用它:

  • 專門用于響應(yīng)通知的 activity。用戶在正常使用應(yīng)用期間不會無緣無故地導(dǎo)航到此 activity滓技,因此該 activity 會啟動新任務(wù)哩牍,而不是添加到應(yīng)用的現(xiàn)有任務(wù)和返回堆棧。這是在上述示例中創(chuàng)建的 intent 類型令漂。

  • 應(yīng)用的常規(guī)應(yīng)用流程中存在的 Activity膝昆。在這種情況下,啟動 activity 會創(chuàng)建一個返回堆棧叠必,以便保留用戶對返回和向上按鈕的預(yù)期荚孵。

從通知啟動 Activity

常規(guī) Activity
這類 Activity 是應(yīng)用的正常用戶體驗流程的一部分。當(dāng)用戶從通知轉(zhuǎn)到 activity 時纬朝,新任務(wù)必須包含完整的返回堆棧收叶,以便用戶點按返回按鈕在應(yīng)用層次結(jié)構(gòu)中向上導(dǎo)航。
特殊 Activity
只有當(dāng) Activity 從通知啟動時共苛,用戶才可以看到此類 Activity判没。從某種意義上講,此 activity 通過提供通知本身難以顯示的信息來擴展通知界面隅茎。此 activity 不需要返回堆棧澄峰。

設(shè)置常規(guī) Activity PendingIntent

如需從通知啟動常規(guī) activity,請使用 TaskStackBuilder 設(shè)置 PendingIntent患膛,以便它可以創(chuàng)建新的返回堆棧摊阀,如下所示。

定義應(yīng)用的 Activity 層次結(jié)構(gòu)

通過向應(yīng)用清單文件中的每個 <activity> 元素添加 android:parentActivityName 屬性踪蹬,定義 activity 的自然層次結(jié)構(gòu)胞此。

<activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<!-- MainActivity is the parent for ResultActivity. -->
<activity
    android:name=".ResultActivity"
    android:parentActivityName=".MainActivity" />
    ...
</activity>
構(gòu)建包含返回堆棧的 PendingIntent

如需啟動包含 activity 返回堆棧的 activity,請創(chuàng)建一個 TaskStackBuilder 實例并調(diào)用 addNextIntentWithParentStack()跃捣,并向其傳遞您要啟動的 activity 的 Intent漱牵。

只要您按照前文所述為每個 activity 定義父 activity肌割,就可以調(diào)用 getPendingIntent() 來接收包含整個返回堆棧的 PendingIntent缩麸。

// Create an Intent for the activity you want to start.
val resultIntent = Intent(this, ResultActivity::class.java)
// Create the TaskStackBuilder.
val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
    // Add the intent, which inflates the back stack.
    addNextIntentWithParentStack(resultIntent)
    // Get the PendingIntent containing the entire back stack.
    getPendingIntent(0,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
}

可以通過調(diào)用 TaskStackBuilder.editIntentAt() 向堆棧中的 Intent 對象添加參數(shù)。有時必須這樣做全度,才能確保返回堆棧中的 activity 在用戶導(dǎo)航到該 activity 時顯示有意義的數(shù)據(jù)娶聘。

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentIntent(resultPendingIntent)
    ...
}
with(NotificationManagerCompat.from(this)) {
    notify(NOTIFICATION_ID, builder.build())
}
設(shè)置特殊 Activity PendingIntent

由于從通知啟動的特殊 activity 不需要返回堆棧闻镶,因此您可以通過調(diào)用 getActivity() 來創(chuàng)建 PendingIntent。不過丸升,請在清單中定義相應(yīng)的任務(wù)選項铆农。

  1. 在清單中,將以下屬性添加到 <activity> 元素中狡耻。

android:taskAffinity= "" 與在代碼中使用的 [FLAG_ACTIVITY_NEW_TASK] 標(biāo)志結(jié)合使用墩剖,將此屬性設(shè)置為空白猴凹,以確保此 activity 不會進入應(yīng)用的默認(rèn)任務(wù)。具有應(yīng)用默認(rèn)親和性的任何現(xiàn)有任務(wù)都不會受到影響岭皂。
android:excludeFromRecents="true"`從“最近使用的應(yīng)用”屏幕中排除新任務(wù)郊霎,以免用戶意外返回該任務(wù)。

val notifyIntent = Intent(this, ResultActivity::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val notifyPendingIntent = PendingIntent.getActivity(
        this, 0, notifyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentIntent(notifyPendingIntent)
    ...
}
with(NotificationManagerCompat.from(this)) {
    notify(NOTIFICATION_ID, builder.build())
}

b.添加操作按鈕

通知最多可以提供三個操作按鈕爷绘,以便用戶快速響應(yīng)书劝,例如暫停提醒或回復(fù)短信。但這些操作按鈕不得重復(fù)用戶點按通知時執(zhí)行的操作揉阎。

帶有一個操作按鈕的通知

添加操作按鈕庄撮,請將 PendingIntent 傳遞給 addAction() 方法。這就像是設(shè)置通知的默認(rèn)點按操作毙籽,除了啟動 activity 之外,您可以執(zhí)行其他操作毡庆,例如啟動在后臺執(zhí)行作業(yè)的 BroadcastReceiver坑赡,這樣該操作就不會中斷已經(jīng)打開的應(yīng)用。

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)

如需詳細了解如何構(gòu)建 BroadcastReceiver 以運行后臺工作么抗,請參閱廣播概覽毅否。

如果您嘗試構(gòu)建包含媒體播放按鈕的通知(例如暫停和跳過曲目),請參閱如何創(chuàng)建包含媒體控件的通知蝇刀。

注意 :在 Android 10(API 級別 29)及更高版本中螟加,如果應(yīng)用不提供自己的通知操作按鈕,平臺會自動生成通知操作按鈕吞琐。如果您不希望應(yīng)用通知顯示任何建議的回復(fù)或操作捆探,可以使用 setAllowGeneratedReplies()setAllowSystemGeneratedContextualActions() 選擇停用系統(tǒng)生成的回復(fù)和操作。

c.添加直接回復(fù)操作

Android 7.0(API 級別 24)中引入的直接回復(fù)操作可讓用戶直接在通知中輸入文本站粟。然后黍图,文本會在不打開 activity 的情況下傳遞給您的應(yīng)用。例如奴烙,您可以使用直接回復(fù)操作助被,讓用戶能夠在通知中回復(fù)短信或更新任務(wù)列表。


點按“Reply”按鈕會打開文本輸入

直接回復(fù)操作在通知中顯示為用于打開文本輸入的附加按鈕切诀。用戶完成輸入后揩环,系統(tǒng)會將文本響應(yīng)附加到您為通知操作指定的 intent,并將該 intent 發(fā)送到您的應(yīng)用幅虑。

添加回復(fù)按鈕

1.創(chuàng)建可添加到通知操作的 RemoteInput.Builder 實例丰滑。此類的構(gòu)造函數(shù)接受系統(tǒng)用作文本輸入鍵的字符串。您的應(yīng)用稍后使用該鍵來檢索輸入的文本翘单。

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

2.為回復(fù)操作創(chuàng)建 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)
  

注意:如果重復(fù)使用 PendingIntent蹦渣,用戶回復(fù)的對話可能不是他們預(yù)期的對話。您必須為每個對話提供不同的請求代碼貌亭,或者提供一個當(dāng)您對任何其他對話的回復(fù) intent 調(diào)用 equals()時不會返回 true 的 intent柬唯。對話 ID 會作為 intent 的 extra 捆綁包的一部分頻繁傳遞,但在您調(diào)用 equals() 時會被忽略圃庭。

3.使用 addRemoteInput()RemoteInput 對象附加到操作锄奢。

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

4.對通知應(yīng)用操作并發(fā)出通知。

  // 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)
  }
  
從回復(fù)中檢索用戶輸入

如需從通知的回復(fù)界面接收用戶輸入剧腻,請調(diào)用 RemoteInput.getResultsFromIntent()拘央,并向其傳遞 BroadcastReceiver 收到的 Intent

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

處理文本后,通過調(diào)用 NotificationManagerCompat.notify() 并使用相同的 ID 和標(biāo)記(如果使用的話)更新通知书在。如需隱藏直接回復(fù)界面灰伟,并向用戶確認(rèn)他們的回復(fù)已正確接收和處理,您必須這樣做儒旬。

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

在處理這個新通知時栏账,請使用傳遞給接收器的 onReceive() 方法的上下文。

通過調(diào)用 setRemoteInputHistory() 將回復(fù)附加到通知底部栈源。不過挡爵,如果您要構(gòu)建即時通訊應(yīng)用,請創(chuàng)建消息式通知甚垦,并將新消息附加到對話中茶鹃。

如需了解有關(guān)即時通訊應(yīng)用通知的更多建議,請參閱即時通訊應(yīng)用最佳實踐部分艰亮。

d.添加進度條

通知可以包含動畫形式的進度指示器闭翩,向用戶顯示正在進行的操作狀態(tài)。


操作期間的進度條

如果您可以估算操作在任何時間的完成進度垃杖,請調(diào)用 setProgress(max, progress, false) 以使用指示符的“確定性”形式(如圖 5 所示)男杈。第一個參數(shù)是“complete”值,例如 100调俘。第二個因素是完成程度伶棒。最后一個表示這是一個確定性進度條。

隨著操作的繼續(xù)彩库,持續(xù)使用更新后的 progress 值調(diào)用 setProgress(max, progress, false) 并重新發(fā)出通知肤无,如以下示例所示。

注意 :由于進度條要求應(yīng)用持續(xù)更新通知骇钦,因此應(yīng)使此代碼在后臺服務(wù)中運行宛渐。

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

操作結(jié)束時,progress 必須等于 max。您可以離開進度條以顯示操作已完成窥翩,也可以將其移除业岁。無論是哪種情況,都請更新通知文本以顯示操作已完成寇蚊。如需移除進度條笔时,請調(diào)用 setProgress(0, 0, false)。

如需顯示不確定的進度條(不指示完成百分比的進度條)仗岸,請調(diào)用 setProgress(0, 0, true)允耿。結(jié)果是,指示器的樣式與前面的進度條相同扒怖,只不過它是一個不指示完成的連續(xù)動畫较锡。在您調(diào)用 setProgress(0, 0, false) 之前,進度動畫會一直運行盗痒,然后更新通知以移除 activity 指示器蚂蕴。

請記得更改通知文本,以表明操作已完成俯邓。

注意 :如果您需要下載文件掂墓,請考慮使用 DownloadManager,它會提供專屬通知來跟蹤下載進度看成。

e.設(shè)置系統(tǒng)范圍的類別

Android 使用預(yù)定義的系統(tǒng)范圍類別來確定當(dāng)用戶啟用勿擾模式時,是否發(fā)出給定通知干擾用戶跨嘉。

如果您的通知屬于 NotificationCompat 中定義的通知類別之一(例如 CATEGORY_ALARM川慌、CATEGORY_REMINDERCATEGORY_EVENTCATEGORY_CALL)祠乃,請通過將相應(yīng)類別傳遞給 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)

系統(tǒng)會根據(jù)這些有關(guān)通知類別的信息來決定是否在設(shè)備處于“勿擾”模式時顯示通知梦重。但是,您無需設(shè)置系統(tǒng)范圍的類別亮瓷。只有當(dāng)您的通知與 NotificationCompat 中定義的某個類別匹配時琴拧,您才應(yīng)執(zhí)行此操作。

f.顯示緊急消息

您的應(yīng)用可能需要顯示緊急的時效性消息嘱支,例如來電或響鈴的鬧鐘蚓胸。在這些情況下,您可以將全屏 intent 與通知相關(guān)聯(lián)除师。

注意 :包含全屏 intent 的通知具有非常強的干擾性沛膳,因此請務(wù)必只將此類通知用于最緊急的時效性消息。

調(diào)用通知后汛聚,用戶會看到以下某種內(nèi)容锹安,具體取決于設(shè)備的鎖定狀態(tài):

  • 如果用戶的設(shè)備處于鎖定狀態(tài),系統(tǒng)會顯示全屏 activity,并覆蓋鎖定屏幕叹哭。
  • 如果用戶的設(shè)備處于解鎖狀態(tài)忍宋,通知會以展開形式顯示,其中包含用于處理或關(guān)閉通知的選項风罩。

注意 :如果您的應(yīng)用以 Android 10(API 級別 29)或更高版本為目標(biāo)平臺糠排,您必須在應(yīng)用的清單文件中請求 USE_FULL_SCREEN_INTENT 權(quán)限,系統(tǒng)才能啟動與時效性通知相關(guān)聯(lián)的全屏 activity泊交。

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)

g.設(shè)置鎖定屏幕公開范圍

如需控制鎖定屏幕中通知的詳細可見信息乳讥,請調(diào)用 setVisibility() 并指定以下值之一:

取值 含義
VISIBILITY_PUBLIC 在鎖定屏幕上顯示通知的完整內(nèi)容
VISIBILITY_SECRET 鎖定屏幕上不會顯示通知的任何部分
VISIBILITY_PRIVATE 鎖定屏幕上僅顯示基本信息,如通知圖標(biāo)和內(nèi)容標(biāo)題廓俭。未顯示通知的完整內(nèi)容

設(shè)置 VISIBILITY_PRIVATE 時云石,您還可以提供隱藏某些詳細信息的備用版本通知內(nèi)容。例如研乒,短信應(yīng)用可能會顯示一條通知汹忠,指出“您有 3 條新短信”,但隱藏了短信內(nèi)容和發(fā)送者雹熬。如需提供此備用通知宽菜,請先照常使用 NotificationCompat.Builder 創(chuàng)建備用通知。然后竿报,使用 setPublicVersion() 將備用通知附加到普通通知中铅乡。

注意,用戶始終可以最終控制其通知是否顯示在鎖定屏幕上烈菌,并且可以根據(jù)應(yīng)用的通知渠道控制通知阵幸。

h.更新通知

如需在發(fā)出通知后對其進行更新,請再次調(diào)用 NotificationManagerCompat.notify()芽世,并向其傳遞您之前使用的相同 ID挚赊。如果之前的通知已關(guān)閉,系統(tǒng)會改為創(chuàng)建新通知济瓢。

您可以選擇調(diào)用 setOnlyAlertOnce()荠割,這樣您的通知只會在用戶首次出現(xiàn)時通過聲音、振動或視覺提示來打斷用戶旺矾,而不適用于后續(xù)更新蔑鹦。

注意:Android 會在更新通知時應(yīng)用速率限制。如果您過于頻繁地發(fā)布通知的更新(不到一秒內(nèi)發(fā)布多項更新)宠漩,系統(tǒng)可能會丟棄更新举反。

i.移除通知

除非發(fā)生以下情況之一,否則通知仍然可見:

  • 用戶關(guān)閉通知扒吁。
  • 如果您在創(chuàng)建通知時調(diào)用了 setAutoCancel()火鼻,用戶便會點按該通知室囊。
  • 您可以針對特定通知 ID 調(diào)用 cancel()。此方法還會刪除持續(xù)性通知魁索。
  • 您調(diào)用了 cancelAll() 方法融撞,該方法將移除之前發(fā)出的所有通知。
  • 如果您在創(chuàng)建通知時使用 setTimeoutAfter() 設(shè)置了超時粗蔚,則會經(jīng)過指定的時長尝偎。如果需要,您可以在指定的超時時長過去之前取消通知鹏控。

j.有關(guān)即時通訊應(yīng)用的最佳做法

為即時通訊和聊天應(yīng)用創(chuàng)建通知時致扯,請考慮此處列出的最佳實踐。

使用 MessagingStyle

從 Android 7.0(API 級別 24)開始当辐,Android 提供了專用于消息內(nèi)容的通知樣式模板抖僵。使用 NotificationCompat.MessagingStyle 類,您可以更改在通知中顯示的多個標(biāo)簽缘揪,包括會話標(biāo)題耍群、其他消息和通知的內(nèi)容視圖。

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

從 Android 9.0(API 級別 28)開始找筝,還需要使用 Person 類才能優(yōu)化通知及其頭像的呈現(xiàn)方式蹈垢。

使用 NotificationCompat.MessagingStyle 時,請執(zhí)行以下操作:

  • 調(diào)用 MessagingStyle.setConversationTitle()袖裕,為超過兩個人的群聊設(shè)置標(biāo)題曹抬。一個好的會話標(biāo)題可以是群聊的名稱,如果沒有名稱急鳄,可以是會話的參與者列表沐祷。否則,消息可能會被誤認(rèn)為屬于與會話中最新消息的發(fā)送者的一對一對話攒岛。
  • 使用 MessagingStyle.setData() 方法包含圖片等媒體消息。支持模式 image/* 的 MIME 類型胞锰。
使用直接回復(fù)
直接回復(fù)可讓用戶以內(nèi)嵌方式回復(fù)消息灾锯。
  • 當(dāng)用戶使用內(nèi)嵌回復(fù)操作回復(fù)后,請使用 MessagingStyle.addMessage() 更新 MessagingStyle 通知嗅榕,并且不要撤消或取消通知顺饮。不取消通知可讓用戶通過通知發(fā)送多次回復(fù)。
  • 如需使內(nèi)嵌回復(fù)操作與 Wear OS 兼容凌那,請調(diào)用 Action.WearableExtender.setHintDisplayInlineAction(true)兼雄。
  • 通過向通知添加歷史消息,使用 addHistoricMessage() 方法為直接回復(fù)對話提供上下文帽蝶。
啟用智能回復(fù)
  • 如需啟用智能回復(fù)赦肋,請對回復(fù)操作調(diào)用 setAllowGeneratedResponses(true)。這樣,當(dāng)通知橋接到 Wear OS 設(shè)備時佃乘,用戶就可以使用智能回復(fù)響應(yīng)囱井。智能回復(fù)響應(yīng)由完全在手表上的機器學(xué)習(xí)模型使用 NotificationCompat.MessagingStyle 通知提供的上下文生成,不會將數(shù)據(jù)上傳到互聯(lián)網(wǎng)來生成響應(yīng)趣避。
添加通知元數(shù)據(jù)

2、可展開樣式的通知

基本通知通常包括標(biāo)題愁拭、一行文本以及用戶可以作為響應(yīng)執(zhí)行的操作讲逛。如需提供更多信息,您可以按照本文檔中介紹的方式應(yīng)用多個通知模板之一敛苇,創(chuàng)建可展開的大型通知妆绞。

首先,使用創(chuàng)建通知中所述的所有基本內(nèi)容構(gòu)建通知枫攀。然后括饶,使用樣式對象調(diào)用 setStyle(),并提供與每個模板相對應(yīng)的信息来涨,如以下示例所示图焰。

a.添加大圖片

如需在通知中添加圖片,請將 NotificationCompat.BigPictureStyle 的實例傳遞給 setStyle()蹦掐。

val notification = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.new_post)
        .setContentTitle(imageTitle)
        .setContentText(imageDescription)
        .setStyle(NotificationCompat.BigPictureStyle()
                .bigPicture(myBitmap))
        .build()

若要使圖片僅在通知收起時顯示為縮略圖(如下圖所示)技羔,請調(diào)用 setLargeIcon() 并向其傳遞圖片。然后卧抗,調(diào)用 BigPictureStyle.bigLargeIcon() 并向其傳遞 null藤滥,這樣大圖標(biāo)就會在通知展開時消失:

使用 NotificationCompat.BigPictureStyle 的通知

b.添加一大段文本

應(yīng)用 NotificationCompat.BigTextStyle 以在通知的展開內(nèi)容區(qū)域顯示文本:

val notification = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.new_mail)
        .setContentTitle(emailObject.getSenderName())
        .setContentText(emailObject.getSubject())
        .setLargeIcon(emailObject.getSenderAvatar())
//BigTextStyle .添加一大段文本
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText(emailObject.getSubjectAndSnippet()))
        .build()
![image.png](https://upload-images.jianshu.io/upload_images/4028253-c00be6042e6a7361.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

提示: 如需為文本添加格式(例如粗體、斜體社裆、換行符等)拙绊,您可以使用 HTML 標(biāo)記添加樣式

c.創(chuàng)建收件箱樣式的通知

如果您想添加多個簡短的摘要行(例如收到的電子郵件中的摘要)泳秀,請對通知應(yīng)用 NotificationCompat.InboxStyle标沪。這樣,您就可以添加多段內(nèi)容文本嗜傅,并且每條文本都截斷為一行金句,而不是由 NotificationCompat.BigTextStyle 提供的一行連續(xù)文本。

如需添加新行吕嘀,最多可調(diào)用 addLine() 六次违寞,如以下示例所示贞瞒。如果添加的代碼行超過 6 行,則僅顯示前 6 行坞靶。

提示 :您可以使用 HTML 標(biāo)記添加樣式(例如加粗主題)憔狞,以區(qū)分每行中的消息主題和消息內(nèi)容。

val notification = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.baseline_email_24)
        .setContentTitle("5 New mails from Frank")
        .setContentText("Check them out")
        .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.logo))
        .setStyle(
                NotificationCompat.InboxStyle()
                .addLine("Re: Planning")
                .addLine("Delivery on its way")
                .addLine("Follow-up")
        )
        .build()
展開后的收件箱樣式通知彰阴。

創(chuàng)建一組通知

從 Android 7.0(API 級別 24)開始瘾敢,您可以在一個組中顯示相關(guān)通知。例如尿这,如果您的應(yīng)用針對收到的電子郵件顯示通知簇抵,請將有關(guān)新電子郵件的所有通知放入同一個群組中,以便它們收起來射众。

如需支持較低版本碟摆,請?zhí)砑诱ㄖ撜ㄖ獙为氾@示叨橱,以匯總所有單獨的通知典蜕。通常,最好使用收件箱樣式的通知來實現(xiàn)此目的罗洗。

收起(頂部)和展開(底部)的通知組

注意 :通知組與通知渠道組不同愉舔。

滿足以下所有條件,請使用通知組:

  • 子通知是完整通知伙菜,可以單獨顯示轩缤,而無需通知組摘要。

  • 單獨顯示子級通知有一個好處贩绕。例如:

    • 它們是可操作的火的,具體操作特定于每條通知。

    • 每條通知中都包含更多信息供用戶查看淑倾。

如果您的通知不符合上述條件馏鹤,不妨考慮使用新信息更新現(xiàn)有通知,或創(chuàng)建消息樣式的通知娇哆,以便在同一對話中顯示多項更新假瞬。

注意 :如果您的應(yīng)用發(fā)出 4 條或更多條通知且未指定通知組,則系統(tǒng)會在 Android 7.0 及更高版本上將這些通知自動分組迂尝。

創(chuàng)建通知組并為其添加通知

如需創(chuàng)建通知組,請為該通知組定義一個唯一標(biāo)識符字符串剪芥。然后垄开,對于您想要添加到通知組中的每條通知,調(diào)用 setGroup() 并傳入通知組名稱税肪。例如:

val GROUP_KEY_WORK_EMAIL = "com.android.example.WORK_EMAIL"

val newMessageNotification = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
        .setSmallIcon(R.drawable.new_mail)
        .setContentTitle(emailObject.getSenderName())
        .setContentText(emailObject.getSubject())
        .setLargeIcon(emailObject.getSenderAvatar())
        .setGroup(GROUP_KEY_WORK_EMAIL)
        .build()

默認(rèn)情況下溉躲,系統(tǒng)會根據(jù)通知的發(fā)布時間對其進行排序榜田,但您可以通過調(diào)用 setSortKey() 更改通知順序。

如果針對某個通知組的提醒必須由其他通知處理锻梳,請調(diào)用 setGroupAlertBehavior()箭券。例如,如果您只希望通知組的摘要發(fā)出通知疑枯,則該通知組中的所有子級都必須具有通知組提醒行為 GROUP_ALERT_SUMMARY辩块。其他選項包括 GROUP_ALERT_ALLGROUP_ALERT_CHILDREN

設(shè)置通知組摘要

分組通知必須有一個額外的通知來充當(dāng)通知組摘要荆永。要啟用分組通知废亭,您必須設(shè)置通知組摘要。此通知組摘要必須包含通知組中其他通知的部分文本具钥,以幫助用戶了解通知組的內(nèi)容豆村。群組摘要的顯示方式取決于 Android 版本:

  • 在低于 7.0(API 級別 24)的 Android 版本中,由于無法顯示嵌套通知組骂删,系統(tǒng)僅顯示您的通知組摘要通知掌动,而隱藏所有其他通知。用戶可以點按群組摘要通知以打開您的應(yīng)用宁玫。

  • 在 Android 7.0 及更高版本中粗恢,系統(tǒng)會將通知組摘要通知顯示為一組嵌套通知,并用每個分組通知的文本摘要進行標(biāo)記撬统。不會顯示您在群組摘要通知中設(shè)置的文本适滓。用戶可以展開嵌套的通知組以查看該組中的各個通知,如上圖 所示恋追。

即使較新版本的 Android 未顯示您設(shè)計的通知組摘要文本凭迹,您也始終需要手動設(shè)置摘要才能啟用分組通知。設(shè)備組摘要的行為在某些設(shè)備類型(例如穿戴式設(shè)備)上可能會有所不同苦囱。在群組摘要中設(shè)置富媒體內(nèi)容有助于在所有設(shè)備和版本上提供最佳體驗嗅绸。

如需添加通知組摘要,請按以下步驟操作:

  1. 創(chuàng)建包含通知組說明的新通知 - 通常最好使用收件箱樣式的通知來完成撕彤。

  2. 通過調(diào)用 setGroup() 將摘要通知添加到通知組中鱼鸠。

  3. 通過調(diào)用 setGroupSummary(true) 指定必須將其用作通知組摘要。

// Use constant ID for notifications used as group summary.
val SUMMARY_ID = 0
val GROUP_KEY_WORK_EMAIL = "com.android.example.WORK_EMAIL"

val newMessageNotification1 = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_notify_email_status)
        .setContentTitle(emailObject1.getSummary())
        .setContentText("You will not believe...")
        .setGroup(GROUP_KEY_WORK_EMAIL)
        .build()

val newMessageNotification2 = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_notify_email_status)
        .setContentTitle(emailObject2.getSummary())
        .setContentText("Please join us to celebrate the...")
        .setGroup(GROUP_KEY_WORK_EMAIL)
        .build()

val summaryNotification = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
        .setContentTitle(emailObject.getSummary())
        // Set content text to support devices running API level < 24.
        .setContentText("Two new messages")
        .setSmallIcon(R.drawable.ic_notify_summary_status)
        // Build summary info into InboxStyle template.
        .setStyle(NotificationCompat.InboxStyle()
                .addLine("Alex Faarborg Check this out")
                .addLine("Jeff Chang Launch Party")
                .setBigContentTitle("2 new messages")
                .setSummaryText("janedoe@example.com"))
        // Specify which group this notification belongs to.
        .setGroup(GROUP_KEY_WORK_EMAIL)
        // Set this notification as the summary for the group.
        .setGroupSummary(true)
        .build()

NotificationManagerCompat.from(this).apply {
    notify(emailNotificationId1, newMessageNotification1)
    notify(emailNotificationId2, newMessageNotification2)
    notify(SUMMARY_ID, summaryNotification)
}

摘要通知 ID 必須保持不變羹铅,以便僅發(fā)布一次蚀狰,以便日后在摘要信息發(fā)生更改時進行更新。后續(xù)向該組添加內(nèi)容會導(dǎo)致更新現(xiàn)有摘要职员。

自動分組

在 Android 7.0(API 級別 24)及更高版本中麻蹋,如果您的應(yīng)用發(fā)送了 4 條或更多通知,并且未指定組鍵或組摘要焊切,系統(tǒng)可能會自動將這些通知分為一組扮授。系統(tǒng)會自動分組顯示通知芳室,并附帶通知組摘要通知,該摘要通知會標(biāo)有某些分組通知的文本片段刹勃。與手動分組的通知一樣堪侯,用戶可以展開此摘要通知以查看各個通知。

自動分組行為在某些設(shè)備類型上可能會有所不同荔仁。為了在所有設(shè)備和版本上提供最佳體驗伍宦,如果您知道通知必須分組,請指定組鍵和組摘要咕晋,以確保這些通知已分組雹拄。

d.在通知中顯示對話

應(yīng)用 NotificationCompat.MessagingStyle 可顯示任意數(shù)量的人之間的依序消息丽惭。這非常適合即時通訊應(yīng)用蔚携,因為它通過單獨處理發(fā)送者名稱和消息文本來為每條消息提供一致的布局捕传,并且每條消息可以多行果复。

如需添加新消息军俊,請調(diào)用 addMessage()诲侮,并傳遞消息文本饶辙、接收時間和發(fā)送者姓名耳幢。您還可以將此信息作為 NotificationCompat.MessagingStyle.Message 對象傳遞

使用 NotificationCompat.MessagingStyle 的通知

使用 NotificationCompat.MessagingStyle 時模暗,為 setContentTitle()setContentText() 指定的任何值都會被忽略禁悠。

您可以調(diào)用 setConversationTitle() 來添加顯示在對話上方的標(biāo)題。這可以是用戶創(chuàng)建的群組名稱兑宇;如果沒有具體名稱碍侦,也可以是對話中的參與者列表。請勿為一對一聊天設(shè)置對話標(biāo)題隶糕,因為系統(tǒng)會利用此字段的存在來提示對話是一個群組瓷产。

此樣式僅適用于搭載 Android 7.0(API 級別 24)及更高版本的設(shè)備。如前所述枚驻,使用兼容性庫 (NotificationCompat) 時濒旦,具有 MessagingStyle 的通知會自動回退為受支持的展開式通知樣式。

為聊天對話創(chuàng)建此類通知時再登,請添加直接回復(fù)操作尔邓。

e.使用媒體控件創(chuàng)建通知

注意 :使用 AndroidX Media3 時,系統(tǒng)會自動創(chuàng)建媒體通知锉矢。

應(yīng)用 MediaStyleNotificationHelper.MediaStyle 可顯示媒體播放控件和曲目信息梯嗽。

在構(gòu)造函數(shù)中指定關(guān)聯(lián)的 MediaSession。這樣沽损,Android 就可以顯示有關(guān)您媒體的正確信息灯节。

調(diào)用 addAction() 最多五次,最多可以顯示五個圖標(biāo)按鈕。調(diào)用 setLargeIcon() 可設(shè)置專輯封面显晶。

與其他通知樣式不同,MediaStyle 還允許您通過指定三個操作按鈕(這些按鈕也會顯示在收起視圖中)來修改收起后尺寸的內(nèi)容視圖壹士。為此磷雇,請向 setShowActionsInCompactView() 提供操作按鈕索引。

val notification = NotificationCompat.Builder(context, CHANNEL_ID)
        // Show controls on lock screen even when user hides sensitive content.
        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
        .setSmallIcon(R.drawable.ic_stat_player)
        // Add media control buttons that invoke intents in your media service
        .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0
        .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1
        .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2
        // Apply the media style template.
        .setStyle(MediaStyleNotificationHelper.MediaStyle(mediaSession)
                .setShowActionsInCompactView(1 /* #1: pause button \*/))
        .setContentTitle("Wonderful music")
        .setContentText("My Awesome Band")
        .setLargeIcon(albumArtBitmap)
        .build()

使用 MediaStyleNotificationHelper.MediaStyle 的通知躏救。

注意 :使用 MediaStyleNotificationHelper.MediaStyle 創(chuàng)建的通知的類別會設(shè)置為 CATEGORY_TRANSPORT唯笙,除非您使用 setCategory() 設(shè)置其他類別。

f.其他資源

如需詳細了解 MediaStyle 和展開式通知盒使,請參閱以下參考文檔崩掘。

3、通話樣式的通知

在 Android 12.0(API 級別 31)及更高版本中少办,系統(tǒng)提供 CallStyle 通知模板苞慢,以將來電通知與其他類型的通知區(qū)分開來。使用此模板可以創(chuàng)建來電或正在進行的通話通知英妓。此模板支持大格式通知挽放,其中包含來電信息和所需的操作(如接聽或拒接來電)。

由于來電和正在進行的通話屬于高優(yōu)先級事件蔓纠,因此這些通知在通知欄中會獲得最高優(yōu)先級辑畦。此排名還使系統(tǒng)能夠?qū)⑦@些優(yōu)先級較高的通話轉(zhuǎn)接到其他設(shè)備。

CallStyle 通知模板包含以下必需操作:

  • 接聽或拒接來電腿倚。
  • 掛斷當(dāng)前通話纯出。
  • 接聽或掛斷電話以過濾來電。
適用于來電和正在進行的通話的 CallStyle 模板

所需操作會以 intent 的形式傳遞敷燎,例如后面幾部分中的 hangupIntentanswerIntent暂筝。其中每個字段都是對系統(tǒng)維護的令牌的引用。令牌是一個輕量級對象懈叹,可以在不同應(yīng)用和進程之間傳遞乖杠。系統(tǒng)負責(zé)管理令牌的生命周期,并確保即使創(chuàng)建 PendingIntent 的應(yīng)用不再運行澄成,它仍然可用胧洒。如果您為另一個應(yīng)用提供 PendingIntent,即表示您授予該應(yīng)用執(zhí)行指定操作的權(quán)限墨状,如拒絕或接聽卫漫。即使創(chuàng)建該 intent 的應(yīng)用當(dāng)前未運行,也會授予此權(quán)限肾砂。如需了解詳情列赎,請參閱 PendingIntent 的參考文檔。

從 Android 14(API 級別 34)開始镐确,您可以將來電通知配置為不可關(guān)閉包吝。為此饼煞,請通過 Notification.Builder#setOngoing(true) 使用 Notification.FLAG_ONGOING_EVENTCallStyle 通知。

// Create a new call, setting the user as the caller.
val incomingCaller = Person.Builder()
    .setName("Jane Doe")
    .setImportant(true)
    .build()
來電

使用 forIncomingCall() 方法為來電創(chuàng)建通話樣式通知诗越。

// Create a call style notification for an incoming call.
val builder = Notification.Builder(context, CHANNEL_ID)
    .setContentIntent(contentIntent)
    .setSmallIcon(smallIcon)
    .setStyle(
         Notification.CallStyle.forIncomingCall(caller, declineIntent, answerIntent))
    .addPerson(incomingCaller)

當(dāng)前通話

使用 forOngoingCall() 方法為正在進行的通話創(chuàng)建通話樣式通知砖瞧。

// Create a call style notification for an ongoing call.
val builder = Notification.Builder(context, CHANNEL_ID)
    .setContentIntent(contentIntent)
    .setSmallIcon(smallIcon)
    .setStyle(
         Notification.CallStyle.forOngoingCall(caller, hangupIntent))
    .addPerson(second_caller)

過濾來電

使用 forScreeningCall() 方法可創(chuàng)建用于過濾來電的調(diào)用樣式通知。

// Create a call style notification for screening a call.
val builder = Notification.Builder(context, CHANNEL_ID)
    .setContentIntent(contentIntent)
    .setSmallIcon(smallIcon)
    .setStyle(
         Notification.CallStyle.forScreeningCall(caller, hangupIntent, answerIntent))
    .addPerson(second_caller)

實現(xiàn)與更多 Android 版本的兼容性

將 API 版本 30 或更低版本的 CallStyle 通知與前臺服務(wù)相關(guān)聯(lián)嚷狞,以便為它們分配 API 級別 31 或更高級別中所指定的最高排名块促。此外,API 版本 30 或更低版本上的 CallStyle 通知可以使用 setColorized() 方法將通知標(biāo)記為彩色床未,從而達到類似排名竭翠。

將 Telecom API 與 CallStyle 通知搭配使用。如需了解詳情薇搁,請參閱 Telecom 框架概覽斋扰。

4、具有時效性的通知

在某些情況下只酥,您的應(yīng)用可能需要緊急吸引用戶的注意力褥实,例如鬧鐘正在響鈴或有來電時。在以搭載 Android 9(API 級別 28)或更低版本的設(shè)備為目標(biāo)平臺的應(yīng)用中裂允,您可以通過在應(yīng)用在后臺運行時啟動 activity 來處理此問題损离。本文檔介紹了如何在搭載 Android 10(API 級別 29)到 Android 13(API 級別 33)的設(shè)備上實現(xiàn)此行為。

添加 POST_NOTIFICATIONS 權(quán)限

從 Android 13 開始绝编,將以下行添加到 AndroidManifest.xml 文件中:

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

創(chuàng)建通知渠道

創(chuàng)建通知渠道以正確顯示通知僻澎,并讓用戶在應(yīng)用設(shè)置中管理通知。如需詳細了解通知渠道十饥,請參閱創(chuàng)建和管理通知渠道窟勃。

Application 類的 onCreate 方法中創(chuàng)建通知渠道:

class DACapp : Application() {
    override fun onCreate() {
        super.onCreate()
        val channel = NotificationChannel(
            CHANNEL_ID,
            "High priority notifications",
            NotificationManager.IMPORTANCE_HIGH
        )

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

當(dāng)用戶首次運行您的應(yīng)用時,他們會在應(yīng)用的應(yīng)用信息系統(tǒng)屏幕中看到如圖 1 所示的內(nèi)容:


應(yīng)用系統(tǒng)設(shè)置中的應(yīng)用信息屏幕中的“通知”部分逗堵。

管理通知權(quán)限

從 Android 13 開始秉氧,請求通知權(quán)限后才能向用戶顯示通知。

val permissionLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.RequestPermission(),
    onResult = { hasNotificationPermission = it }
)
...
Button(
    onClick = {
        if (!hasNotificationPermission) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
        }
    },
) {
    Text(text = "Request permission")
}
通知權(quán)限請求的系統(tǒng)對話框
已授予通知權(quán)限

創(chuàng)建高優(yōu)先級通知

創(chuàng)建通知時蜒秤,請?zhí)砑用枋鲂詷?biāo)題和消息汁咏。

private fun showNotification() {
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    val notificationBuilder =
        NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.baseline_auto_awesome_24)
            .setContentTitle("HIGH PRIORITY")
            .setContentText("Check this dog puppy video NOW!")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_RECOMMENDATION)

    notificationManager.notify(666, notificationBuilder.build())
}

向用戶顯示通知

Button(onClick = { showNotification() }) {
    Text(text = "Show notification")
}

高優(yōu)先級通知

持續(xù)性通知

當(dāng)您向用戶顯示通知時,他們可以確認(rèn)或關(guān)閉應(yīng)用的提醒作媚。例如攘滩,用戶可以接聽或拒絕來電。

注意 :當(dāng)用戶使用設(shè)備時纸泡,系統(tǒng)界面可能會顯示浮動通知漂问,而不是啟動全屏 intent。

如果您的通知正在進行(例如來電),請將該通知與前臺服務(wù)相關(guān)聯(lián)蚤假。以下代碼段展示了如何顯示與前臺服務(wù)關(guān)聯(lián)的通知:

// Provide a unique integer for the "notificationId" of each notification.
startForeground(notificationId, notification)

5栏饮、自定義樣式通知

為了使通知在不同的 Android 版本上呈現(xiàn)最佳效果,請使用標(biāo)準(zhǔn)通知模板來構(gòu)建通知磷仰。如果您想在通知中提供更多內(nèi)容抡爹,不妨考慮使用某個可展開的通知模板

不過芒划,如果系統(tǒng)模板無法滿足您的需求,您可以使用自己的通知布局欧穴。

注意 :使用自定義通知布局時民逼,請?zhí)貏e注意確保您的自定義布局適用于不同的設(shè)備屏幕方向和分辨率。雖然此建議適用于所有界面布局涮帘,但對于通知尤為重要拼苍,因為抽屜式通知欄中的空間有限。自定義通知布局的可用高度取決于 Android 版本调缨。在某些版本中疮鲫,收起視圖布局可低至 48 dp,浮動視圖布局可低至 88 dp弦叶,展開視圖布局可低至 252 dp俊犯。

為內(nèi)容區(qū)域創(chuàng)建自定義布局

如果您需要自定義布局,可以將 NotificationCompat.DecoratedCustomViewStyle 應(yīng)用于通知伤哺。借助此 API燕侠,您可以為通常由標(biāo)題和文本內(nèi)容占據(jù)的內(nèi)容區(qū)域提供自定義布局,同時仍對通知圖標(biāo)立莉、時間戳绢彤、子文本和操作按鈕使用系統(tǒng)裝飾。

此 API 的工作方式與可展開的通知模板類似蜓耻,都是基于基本通知布局構(gòu)建茫舶,如下所示:

  1. 使用 NotificationCompat.Builder 構(gòu)建基本通知
  2. 調(diào)用 setStyle()刹淌,并向其傳遞 NotificationCompat.DecoratedCustomViewStyle 的實例饶氏。
  3. 將自定義布局膨脹為 RemoteViews 的實例。
  4. 調(diào)用 setCustomContentView() 以設(shè)置收起后通知的布局芦鳍。
  5. 您還可以選擇調(diào)用 setCustomBigContentView()嚷往,為展開式通知設(shè)置不同的布局。

注意 :如果您要為媒體播放控件創(chuàng)建自定義通知柠衅,請遵循相同的建議皮仁,但請改用 NotificationCompat.DecoratedMediaCustomViewStyle 類。

準(zhǔn)備布局

需要使用 small 和 large 布局。在此示例中贷祈,small 布局可能如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/notification_title"
        style="@style/TextAppearance.Compat.Notification.Title"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Small notification, showing only a title" />
</LinearLayout>

large 布局可能如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/notification_title"
        style="@style/TextAppearance.Compat.Notification.Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Large notification, showing a title and a body." />

    <TextView
        android:id="@+id/notification_body"
        style="@style/TextAppearance.Compat.Notification.Line2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="This is the body. The height is manually forced to 300dp." />
</LinearLayout>
構(gòu)建并顯示通知
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

// Get the layouts to use in the custom notification.
val notificationLayout = RemoteViews(packageName, R.layout.notification_small)
val notificationLayoutExpanded = RemoteViews(packageName, R.layout.notification_large)

// Apply the layouts to the notification.
val customNotification = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setStyle(NotificationCompat.DecoratedCustomViewStyle())
        .setCustomContentView(notificationLayout)
        .setCustomBigContentView(notificationLayoutExpanded)
        .build()

notificationManager.notify(666, customNotification)

注意趋急,通知的背景顏色可能因設(shè)備和版本而異。在自定義布局中势誊,對文本應(yīng)用 TextAppearance_Compat_Notification 樣式呜达,對標(biāo)題應(yīng)用 TextAppearance_Compat_Notification_Title 等支持庫樣式,如以下示例所示粟耻。這些樣式會根據(jù)顏色變化進行調(diào)整查近,因此您最終不會出現(xiàn)黑底白字或白底文字的情況。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:text="@string/notification_title"
    android:id="@+id/notification_title"
    style="@style/TextAppearance.Compat.Notification.Title" />

避免在 RemoteViews 對象上設(shè)置背景圖片挤忙,否則文字可能會無法讀取霜威。

使用其他應(yīng)用時,系統(tǒng)會顯示一個小型通知布局
使用其他應(yīng)用時册烈,系統(tǒng)會顯示大的通知布局

通知超時時間結(jié)束后戈泼,通知僅會顯示在系統(tǒng)欄中


小通知布局在系統(tǒng)欄中的顯示方式
系統(tǒng)欄中會顯示一個大的通知布局

創(chuàng)建完全自定義的通知布局

注意 :以 Android 12(API 級別 31)或更高版本為目標(biāo)平臺的應(yīng)用無法創(chuàng)建完全自定義的通知。相反赏僧,系統(tǒng)會應(yīng)用與 Notification.DecoratedCustomViewStyle 的行為幾乎完全相同的標(biāo)準(zhǔn)模板大猛。

如果您不想使用標(biāo)準(zhǔn)通知圖標(biāo)和標(biāo)題裝飾通知,請按照上述步驟操作淀零,但不要調(diào)用 setStyle()挽绩。

注意: 我們不建議使用未經(jīng)修飾的通知,因為這種通知與其他通知不匹配驾中,并且在對通知區(qū)域應(yīng)用了不同樣式的設(shè)備上可能導(dǎo)致嚴(yán)重的布局兼容性問題琼牧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哀卫,隨后出現(xiàn)的幾起案子巨坊,更是在濱河造成了極大的恐慌,老刑警劉巖此改,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趾撵,死亡現(xiàn)場離奇詭異,居然都是意外死亡共啃,警方通過查閱死者的電腦和手機占调,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來移剪,“玉大人究珊,你說我怎么就攤上這事∽菘粒” “怎么了剿涮?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵言津,是天一觀的道長。 經(jīng)常有香客問我取试,道長悬槽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任瞬浓,我火速辦了婚禮初婆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猿棉。我一直安慰自己磅叛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布萨赁。 她就那樣靜靜地躺著宪躯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪位迂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天详瑞,我揣著相機與錄音掂林,去河邊找鬼。 笑死坝橡,一個胖子當(dāng)著我的面吹牛泻帮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播计寇,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锣杂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了番宁?” 一聲冷哼從身側(cè)響起元莫,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝶押,沒想到半個月后踱蠢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡棋电,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年茎截,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赶盔。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡企锌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出于未,到底是詐尸還是另有隱情撕攒,我是刑警寧澤陡鹃,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站打却,受9級特大地震影響杉适,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柳击,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一猿推、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捌肴,春花似錦蹬叭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饥悴,卻和暖如春坦喘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背西设。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工瓣铣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贷揽。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓棠笑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親禽绪。 傳聞我的和親對象是個殘疾皇子蓖救,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容