在 Android 應用程式中接收訊息

Firebase 通知的行為會因接收應用程式的前景/背景狀態而有所不同。如果您希望前景應用程式接收通知訊息或資料訊息,就必須編寫程式碼來處理 onMessageReceived 回呼。如要瞭解通知和資料訊息之間的差異,請參閱「訊息類型」。

處理訊息

如要接收訊息,請使用擴充 FirebaseMessagingService 的服務。您的服務應覆寫 onMessageReceivedonDeletedMessages 回呼。

處理訊息的時間視窗可能會短於 20 秒,這取決於呼叫 onMessageReceived 前發生的延遲時間,包括作業系統延遲、應用程式啟動時間、主執行緒遭其他作業阻斷,或先前 onMessageReceived 呼叫耗費過多時間。超過這段時間後,各種 OS 行為 (例如 Android 的程序終止或 Android O 的 背景執行限制) 可能會影響您完成工作的可能性。

onMessageReceived 適用於大多數郵件類型,但以下類型除外:

  • 在應用程式於背景運作期間傳送通知訊息。在這種情況下,系統會將通知傳送至裝置的系統匣。使用者輕觸通知後,系統預設會開啟應用程式啟動器。

  • 在背景接收的訊息,其中包含通知和資料酬載。在這種情況下,系統會將通知傳送至裝置的系統通知格,並在啟動器活動的意圖額外項目中傳送資料酬載。

簡單來說:

應用程式狀態 通知 資料 兩者並用
前景 onMessageReceived onMessageReceived onMessageReceived
背景 系統匣 onMessageReceived 通知:系統通知區
資料:意圖的額外資料。
如要進一步瞭解訊息類型,請參閱「通知和資料訊息」。

編輯應用程式資訊清單

如要使用 FirebaseMessagingService,您必須在應用程式資訊清單中新增下列內容:

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

此外,建議您設定預設值,自訂通知的外觀。您可以指定自訂預設圖示和自訂預設顏色,在通知酬載中未設定等值時套用。

application 標記中新增以下行,設定自訂預設圖示和自訂顏色:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Android 會顯示自訂預設圖示

  • 所有透過 通知編輯器傳送的通知訊息。
  • 任何未在通知酬載中明確設定圖示的通知訊息。

Android 會使用自訂預設顏色

  • 所有透過 通知編輯器傳送的通知訊息。
  • 任何未在通知酬載中明確設定顏色的通知訊息。

如果未設定自訂的預設圖示,且通知酬載中也未設定圖示,Android 會顯示以白色顯示的應用程式圖示。

覆寫 onMessageReceived

您可以覆寫 FirebaseMessagingService.onMessageReceived 方法,根據收到的 RemoteMessage 物件執行動作,並取得訊息資料:

Kotlin+KTX

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob()
        } else {
            // Handle message within 10 seconds
            handleNow()
        }
    }

    // Check if message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

覆寫 onDeletedMessages

在某些情況下,FCM 可能無法傳送訊息。發生這種情況的原因是,在特定裝置連線時,應用程式有太多 (超過 100 則) 待處理訊息,或是裝置在一個多月內未連線至 FCM。在這些情況下,您可能會收到 FirebaseMessagingService.onDeletedMessages() 的回呼。當應用程式執行個體收到這項回呼時,應會與應用程式伺服器執行完整同步處理。如果您在過去 4 週內未向該裝置上的應用程式傳送訊息,FCM 就不會呼叫 onDeletedMessages()

在背景應用程式中處理通知訊息

當應用程式處於背景執行時,Android 會將通知訊息導向系統匣。使用者輕觸通知後,系統會根據預設開啟應用程式啟動器。

這包括同時包含通知和資料酬載的訊息 (以及透過「通知」資訊主頁傳送的所有訊息)。在這些情況下,系統會將通知傳送至裝置的系統通知區,並在啟動器活動的意圖額外項目中傳送資料酬載。

如要深入瞭解應用程式訊息的傳送情形,請參閱 FCM 報表資訊主頁,這可記錄在 Apple 和 Android 裝置上傳送及開啟的訊息數量,以及 Android 應用程式「曝光次數」(使用者看到的通知) 資料。

在直接啟動模式下接收 FCM 訊息

如果開發人員想在裝置解鎖前,就將 FCM 訊息傳送至應用程式,可以讓 Android 應用程式在裝置處於直接啟動模式時接收訊息。舉例來說,您可能希望應用程式的使用者即使在鎖定的裝置上,也能收到鬧鐘通知。

建構此用途時,請遵守一般直接啟動模式的最佳做法和限制。特別重要的是,請考量啟用直接啟動功能的訊息可見度,因為任何有權存取裝置的使用者都能查看這些訊息,無須輸入使用者憑證。

事前準備

  • 裝置必須設定為直接啟動模式。
  • 裝置必須安裝最新版本的 Google Play 服務 (19.0.54 以上版本)。
  • 應用程式必須使用 FCM SDK (com.google.firebase:firebase-messaging) 才能接收 FCM 訊息。

在應用程式中啟用直接啟動模式訊息處理功能

  1. 在應用程式層級的 Gradle 檔案中,新增 FCM 直接啟動支援程式庫的依附元件:

    implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
    
  2. 在應用程式資訊清單中新增 android:directBootAware="true" 屬性,讓應用程式的 FirebaseMessagingService 能偵測直接啟動:

    <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false"
        android:directBootAware="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    

請務必確保這個 FirebaseMessagingService 可在直接啟動模式下執行。請確認下列需求條件:

  • 服務在直接啟動模式下執行時,不應存取憑證保護的儲存空間。
  • 服務不應嘗試使用 ActivitiesBroadcastReceivers 或其他 Services 等元件,因為這些元件在直接啟動模式下執行時,並未標示為具備直接啟動感知特性。
  • 服務使用的任何程式庫,在直接啟動模式下執行時,不得存取憑證保護的儲存空間,也不得呼叫非直接啟動感知元件。這表示應用程式使用的任何從服務呼叫的程式庫,都必須具備直接啟動感知特性,或者應用程式必須檢查是否在直接啟動模式下執行,並且不會在該模式下呼叫這些程式庫。舉例來說,Firebase SDK 可搭配直接啟動功能運作 (可納入應用程式,且不會在直接啟動模式下發生當機情形),但許多 Firebase API 不支援在直接啟動模式下呼叫。
  • 如果應用程式使用自訂 ApplicationApplication 也必須支援直接啟動 (在直接啟動模式下無法存取憑證保護的儲存空間)。

如要瞭解如何在直接啟動模式下傳送訊息給裝置,請參閱「傳送啟用直接啟動功能的訊息」。