在 Android 應用程式中接收訊息

Firebase 通知的行為有所不同,具體取決於接收應用程式的前台/後台狀態。如果您希望前台應用程式接收通知訊息或資料訊息,則需要編寫程式碼來處理onMessageReceived回呼。有關通知訊息和資料訊息之間差異的說明,請參閱訊息類型

處理訊息

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

處理訊息的時間視窗可能會短於 20 秒,具體取決於在呼叫onMessageReceived之前發生的延遲,包括作業系統延遲、應用程式啟動時間、主執行緒被其他操作阻塞或之前的onMessageReceived呼叫花費太長時間。此後,各種作業系統行為(例如 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) 或該裝置超過 1 個月沒有連接到 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
  • 在直接啟動模式下運作時,該服務使用的任何程式庫也不得存取受憑證保護的存儲,也不得呼叫非 directBootAware 元件。這意味著應用程式使用的從服務呼叫的任何程式庫要么需要直接啟動感知,要么應用程式需要檢查它是否在直接啟動模式下運行,而不是在該模式下調用它們。例如,Firebase SDK 支援直接啟動(它們可以包含在應用程式中,而不會在直接啟動模式下崩潰),但許多 Firebase API 不支援在直接啟動模式下呼叫。
  • 如果應用程式使用自訂Application ,則該Application還需要支援直接啟動(在直接啟動模式下無法存取受憑證保護的儲存空間)。

有關在直接啟動模式下傳送訊息至裝置的指南,請參閱傳送啟用直接啟動的訊息