使用 FCM AndroidConfigV2,您可以傳送意圖導向訊息至 Android 裝置,並及時傳送通知和簡化 API。
本指南說明如何將後端傳送要求從 AndroidConfig 遷移至 AndroidConfigV2,以及如何將 Android 應用程式用戶端從舊版 onMessageReceived 處理方式更新為新的第 2 版用戶端回呼 onNotificationReceived 和 onBackgroundSyncReceived。
AndroidConfigV2 的新功能
FCM AndroidConfigV2 API 推出兩種訊息類型,簡化開發人員體驗:
RemoteNotification:建議用於所有顯示緊急、具時效性且使用者可見通知的 FCM 訊息。這類訊息會略過所有省電措施,並立即傳送。在裝置上,FCM SDK 和 Google Play 服務會負責將通知發布至 Android 的NotificationManager。BackgroundSync:非緊急資料訊息,用於背景同步處理和應用程式狀態更新。系統可能會批次或延遲傳送,以盡可能延長電池續航力。
| 功能 | 舊版 (AndroidConfig 第 1 版) |
新 (AndroidConfigV2) |
|---|---|---|
| 設定欄位 | message.android |
message.android_v2 |
| 優先檔案區定義 | 明確的 priority: "high" 或 priority: "normal" |
由聯合型別暗示 (remote_notification 用於緊急警示,background_sync 用於非緊急同步) |
| 通知發布 | 應用程式手動呼叫 NotificationManager.notify() |
FCM SDK 和 GMS Core 直接或使用 NotificationResponse 發布 |
| 用戶端回呼 | • onMessageReceived(RemoteMessage)• onDeletedMessages() |
• onNotificationReceived(RemoteMessage)• onBackgroundSyncReceived(RemoteMessage)• onDeletedMessages() |
| 可收合性 | 不一;必須明確設定 | 這兩種訊息類型都可以是可收合或不可收合 (預設為不可收合) |
授權 AndroidConfigV2 傳送要求
您可以繼續使用透過 Google 應用程式預設憑證或 Admin SDK,從 Firebase 服務帳戶衍生的 OAuth 2.0 存取權杖,並將 POST 要求傳送至 HTTP v1 messages:send 端點。
如果不是使用 Firebase 服務帳戶,請務必將專用帳戶指派給 Firebase 雲端通訊 API 管理員角色 (roles/firebase.messagingAdmin),並在建立存取權杖時要求 https://www.googleapis.com/auth/firebase.messaging OAuth 2.0 範圍:
POST https://fcm.googleapis.com/v1/projects/YOUR_PROJECT_ID/messages:send HTTP/1.1
Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN
Content-Type: application/json
更新伺服器傳送要求 (REST)
如要使用 REST API 傳送 AndroidConfigV2 要求,請將要求主體中的 android 物件替換為 android_v2。在 android_v2 中,指定常用參數 (例如 ttl、collapse_key、data 和 restricted_package_name),並提供下列其中一個聯集欄位:remote_notification 或 background_sync。
傳送 RemoteNotification 訊息
如要傳送緊急的面向使用者通知,請加入 remote_notification 物件和建議的 notification 酬載。mutable_content 預設為 false。GMS Core 會立即轉譯通知並發布到系統匣,不會執行背景應用程式程式碼。
完整 HTTP 要求 JSON 範例 (自動算繪通知)
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message": {
"token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification": {
"title": "FCM Message",
"body": "This is an FCM notification message!"
},
"android_v2": {
"ttl": "3600s",
"remote_notification": {
"mutable_content": false,
"notification": {
"title": "Order update",
"body": "Your order has been shipped!",
"icon": "ic_notification_custom",
"sound": "default",
"tag": "alert_tag_1",
"id": 100
}
}
}
}
}
傳送含有可變內容的 RemoteNotification
如果應用程式需要在裝置上顯示通知前修改通知,請在 remote_notification 中設定 mutable_content: true。這會指示 GMS Core 繫結至用戶端應用程式,並叫用 onNotificationReceived()。如要解密端對端加密酬載、附加使用者顯示圖片或本地化字串,這項功能就非常實用。
即使 mutable_content 為 true,也請務必在 remote_notification 中加入 notification 物件。如果用戶端回呼逾時或超過抑制限制,GMS Core 會使用這個 notification 物件做為備用通知。
如果您是從舊版 v1 資料訊息遷移,且希望 FCM 將酬載以純資料訊息的形式傳送至舊版 v1 用戶端安裝,請在 remote_notification 內設定 use_as_v1_data_message: true。
完整的 HTTP 要求 JSON 範例
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message": {
"token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data": {
"encrypted_content": "U2FsdGVkX19vN2m+",
"sender_id": "user_98124"
},
"android_v2": {
"ttl": "3600s",
"remote_notification": {
"mutable_content": true,
"use_as_v1_data_message": true,
"notification": {
"title": "New message",
"body": "You have a new message",
"tag": "chat_alert",
"id": 1001
}
}
}
}
}
傳送 BackgroundSync 訊息
如要傳送非緊急訊息,用於背景資料同步、靜音狀態更新,或更新應用程式徽章或小工具,請使用 background_sync 物件。請勿使用這類訊息發布使用者可見的通知,因為這類訊息可能會批次處理或延遲,以最佳化裝置電池續航力。
完整的 HTTP 要求 JSON 範例
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message": {
"token": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data": {
"score": "FETCH_UPDATES",
"sync_action": "FETCH_UPDATES"
},
"android_v2": {
"ttl": "86400s",
"collapse_key": "app_state_sync",
"background_sync": {}
}
}
}
更新 Android 用戶端回呼
如要在 Android 上接收AndroidConfigV2訊息,請升級應用程式,改用最新版 firebase-messaging SDK。請實作 onNotificationReceived() 和 onBackgroundSyncReceived(),更新擴充 FirebaseMessagingService 的服務。
安裝 EAP SDK
在 EAP 期間,firebase-messaging v2 SDK 會以本機 Maven 存放區封存檔的形式發布,而非透過 Google 的公開 Maven 存放區。
使用下列任一選項,將包含
firebase-messaging:26.1.0-eap01的m2repository目錄 新增至 Android 專案的根目錄 (<project-root>/m2repository) :- 方法 A:下載預先建構的封存檔:下載 FirebaseMessaging_26.1.0-eap01.zip,然後將
m2repository目錄解壓縮至 Android 專案的根目錄 (<project-root>/m2repository)。 方法 B:使用 Gradle 從 GitHub 建構:複製
firebase/firebase-android-sdk的feature/fcm-android-config-v2-eap分支版本、建構本機 Maven 存放區,然後將產生的build/m2repository目錄複製到 Android 專案根目錄:git clone --branch feature/fcm-android-config-v2-eap --single-branch \ https://github.com/firebase/firebase-android-sdk.git cd firebase-android-sdk ./gradlew -PprojectsToPublish="firebase-messaging" firebasePublish cp -R build/m2repository /path/to/your/android-project/m2repository
- 方法 A:下載預先建構的封存檔:下載 FirebaseMessaging_26.1.0-eap01.zip,然後將
在專案層級的
settings.gradle.kts(或settings.gradle) 中,將本機m2repository目錄新增至repositories區塊頂端,位於google()上方:Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url = uri("${rootDir}/m2repository") } google() mavenCentral() } }Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url "${rootDir}/m2repository" } google() mavenCentral() } }在模組層級
app/build.gradle.kts(或app/build.gradle) 中,將firebase-messaging依附元件更新為26.1.0-eap01:Kotlin
dependencies { implementation("com.google.firebase:firebase-messaging:26.1.0-eap01") }Groovy
dependencies { implementation 'com.google.firebase:firebase-messaging:26.1.0-eap01' }將專案與 Gradle 檔案同步處理。
使用 onNotificationReceived 處理 RemoteNotifications
使用 AndroidConfigV2 時,除非 mutable_content 設為 true,或在 onNotificationReceived() 中明確設為靜音,否則系統會顯示 RemoteNotification 訊息。
當 RemoteNotification 帶著 mutable_content: true 抵達時,GMS Core 會繫結至您的應用程式並呼叫 onNotificationReceived()。方法必須在 20 秒內傳回 NotificationResponse。
傳回修改後的通知
您傳遞至 NotificationResponse.create 的 Notification 物件會取代傳送要求中定義的伺服器 remote_notification.notification 備用酬載屬性。如要保留傳送要求中的值,請在套用裝置端修改時,從 message.notification (Java 中的 message.getNotification()) 讀取這些值:
Kotlin
import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.NotificationResponse
import com.google.firebase.messaging.RemoteMessage
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
val serverNotif = message.notification
val channelId = serverNotif?.channelId ?: "default_channel"
// Keep the server-defined title unchanged, or fall back to default
val title = serverNotif?.title ?: "New message"
// Modify the notification body on-device (for example, decrypting data)
val decryptedBody = decryptPayload(message.data["encrypted_content"])
val builder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_notification)
.setContentTitle(title)
.setContentText(decryptedBody)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
// Return the response for the open-source FCM SDK to post to the Android platform
return NotificationResponse.create("optional_tag", 100, builder.build())
}
}
Java
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.google.firebase.messaging.NotificationResponse;
import androidx.core.app.NotificationCompat;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
RemoteMessage.Notification serverNotif = message.getNotification();
String channelId = (serverNotif != null && serverNotif.getChannelId() != null)
? serverNotif.getChannelId()
: "default_channel";
// Keep the server-defined title unchanged, or fall back to default
String title = (serverNotif != null && serverNotif.getTitle() != null)
? serverNotif.getTitle()
: "New message";
// Modify the notification body on-device (for example, decrypting data)
String decryptedBody = decryptPayload(message.getData().get("encrypted_content"));
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_notification)
.setContentTitle(title)
.setContentText(decryptedBody)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
// Return the response for the open-source FCM SDK to post to the Android platform
return NotificationResponse.create("optional_tag", 100, builder.build());
}
}
隱藏通知
如果使用者目前正在使用相關畫面或聊天室,您可以傳回 NotificationResponse.suppress() 來隱藏通知:
Kotlin
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
val chatId = message.data["chat_id"]
val isAppForeground = ProcessLifecycleOwner.get()
.lifecycle
.currentState
.isAtLeast(Lifecycle.State.STARTED)
if (isAppForeground && chatRepository.isConversationActive(chatId)) {
// Suppress notification display because the user is actively viewing this chat
return NotificationResponse.suppress()
}
val builder = buildNotificationForChat(message)
return NotificationResponse.create("chat_tag", 101, builder.build())
}
Java
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.ProcessLifecycleOwner;
@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
String chatId = message.getData().get("chat_id");
boolean isAppForeground = ProcessLifecycleOwner.get()
.getLifecycle()
.getCurrentState()
.isAtLeast(Lifecycle.State.STARTED);
if (isAppForeground && chatRepository.isConversationActive(chatId)) {
// Suppress notification display because the user is actively viewing this chat
return NotificationResponse.suppress();
}
NotificationCompat.Builder builder = buildNotificationForChat(message);
return NotificationResponse.create("chat_tag", 101, builder.build());
}
串流通知或取消舊警報 (FcmNotificationManager)
如需針對單一傳入推播發布多則通知,或在顯示新通知前取消過時通知,請使用 FcmNotificationManager:
Kotlin
override fun onNotificationReceived(message: RemoteMessage): NotificationResponse {
// Retrieve the scoped manager for this message execution
val manager = getFcmNotificationManager(message)
// 1. Cancel an outdated notification right away
manager.cancelNow("message_tag", 50)
// 2. Post the item notification immediately
val itemNotif = NotificationCompat.Builder(this, "chat_channel")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("Alex")
.setContentText(message.data["text"])
manager.postNow("item_tag", 51, itemNotif.build())
// 3. Post a group summary notification
val summaryNotif = NotificationCompat.Builder(this, "chat_channel")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("New Conversations")
.setGroupSummary(true)
manager.postNow("summary_tag", 52, summaryNotif.build())
// 4. Return finished() to complete the streaming workflow
return manager.finished()
}
Java
@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
// Retrieve the scoped manager for this message execution
FcmNotificationManager manager = getFcmNotificationManager(message);
// 1. Cancel an outdated notification right away
manager.cancelNow("message_tag", 50);
// 2. Post the item notification immediately
NotificationCompat.Builder itemNotif = new NotificationCompat.Builder(this, "chat_channel")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("Alex")
.setContentText(message.getData().get("text"));
manager.postNow("item_tag", 51, itemNotif.build());
// 3. Post a group summary notification
NotificationCompat.Builder summaryNotif = new NotificationCompat.Builder(this, "chat_channel")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("New Conversations")
.setGroupSummary(true);
manager.postNow("summary_tag", 52, summaryNotif.build());
// 4. Return finished() to complete the streaming workflow
return manager.finished();
}
使用 onBackgroundSyncReceived 處理 BackgroundSync 訊息
如要在 Android 上處理 BackgroundSync 訊息,請使用 onBackgroundSyncReceived():
Kotlin
override fun onBackgroundSyncReceived(message: RemoteMessage) {
val syncCommand = message.data["sync_action"]
try {
// Perform local database synchronization or cache refresh
AppDataRepository.getInstance(applicationContext).syncWithServer(syncCommand)
} catch (e: Exception) {
Log.e("FCM", "Background sync operation failed", e)
}
// Execution completes -> GMS Core marks the message as handled and unbinds.
}
Java
@Override
public void onBackgroundSyncReceived(RemoteMessage message) {
String syncCommand = message.getData().get("sync_action");
try {
// Perform local database synchronization or cache refresh
AppDataRepository.getInstance(getApplicationContext()).syncWithServer(syncCommand);
} catch (Exception e) {
Log.e("FCM", "Background sync operation failed", e);
}
// Execution completes -> GMS Core marks the message as handled and unbinds.
}
使用 onDeletedMessages 處理待刪除的訊息
在某些情況下,例如裝置長時間未連線至 FCM,或伺服器佇列已滿,FCM 可能會在傳送前刪除待處理訊息。在這種情況下,請覆寫 onDeletedMessages():
Kotlin
override fun onDeletedMessages() {
// Perform a full state synchronization with your app server
AppDataRepository.getInstance(applicationContext).scheduleFullSync()
}
Java
@Override
public void onDeletedMessages() {
// Perform a full state synchronization with your app server
AppDataRepository.getInstance(getApplicationContext()).scheduleFullSync();
}
遷移特定應用程式
傳送端對端加密 (E2EE) 通知
使用 RemoteNotification 傳送端對端加密通知時,解密的通知內容會保留在應用程式和 Android 平台中:
- 傳送可變動通知:伺服器會傳送
RemoteNotification,其中包含mutable_content: true、data中的加密酬載,以及一般未加密備份notification。GMS Core 會將加密訊息傳送至應用程式中的開放原始碼 FCM SDK。 - 解密並傳回通知:FCM SDK 會叫用
onNotificationReceived()。應用程式會在本機解密酬載,建構最終解密的 AndroidNotification,並使用NotificationResponse或FcmNotificationManager將其傳回開放原始碼 FCM SDK。 - 發布至平台並回報中繼資料:開放原始碼 FCM SDK 會直接將解密的通知發布至 Android 平台
NotificationManagerAPI,並僅將通知中繼資料 (例如通知 ID 和時間戳記) 傳回 GMS Core,以便觀測傳送情形。解密後的內容絕不會傳送至 GMS Core。 - 視需要發布備份通知:只有在應用程式未在 20 秒逾時內回應,或超出背景抑制限制時,GMS Core 才會直接將一般備份
notification發布至 Android 平台。

瞭解通知抑制和逾時
為確保 Android 生態系統中的訊息傳遞可靠,GMS Core 在處理 RemoteNotification 訊息時,會套用處理逾時和通知抑制限制:
處理逾時
如果 mutable_content 設為 true,onNotificationReceived() 方法必須在 20 秒內傳回 NotificationResponse。如果執行時間超過這個門檻,系統會取消回呼,GMS Core 則會自動發布從 remote_notification.notification 酬載轉譯的備用通知。
通知抑制率
由於 RemoteNotification 訊息會略過 Doze 限制,立即提醒使用者並立即傳送,因此應用程式應會顯示收到的 RemoteNotification 訊息通知。
每個應用程式在背景執行時,最多可抑制 25% 的 RemoteNotification 流量。如果應用程式的抑制率超過 25%,GMS Core 會自動顯示並發布從 remote_notification.notification 酬載轉譯的備用通知。
應用程式在前景執行時,系統不會將抑制次數計入這項門檻。此外,如果應用程式獲授予不受限制的背景使用權限,也不會受到背景抑制限制。