FCM AndroidConfigV2 を使用すると、タイムリーな通知配信と簡素化された API を使用して、インテント駆動型のメッセージを Android デバイスに送信できます。
このガイドでは、バックエンドの送信リクエストを AndroidConfig から AndroidConfigV2 に移行する方法と、Android アプリケーション クライアントを従来の onMessageReceived 処理から新しい v2 クライアント コールバック onNotificationReceived と onBackgroundSyncReceived に更新する方法について説明します。
AndroidConfigV2 の新機能
FCM AndroidConfigV2 API では、次の 2 つのメッセージ タイプが導入され、デベロッパー エクスペリエンスが簡素化されています。
RemoteNotification: 緊急性が高く、時間制限のあるユーザーに表示される通知を表示するすべての FCM メッセージに推奨されます。これらのメッセージはバッテリー節約対策をバイパスし、遅延なく配信されます。デバイスでは、FCM SDK と Google Play 開発者サービスが、Android のNotificationManagerへの通知の投稿を管理します。BackgroundSync: バックグラウンド同期とアプリの状態の更新を目的とした、緊急性のないデータ メッセージ。バッテリー駆動時間を最適化するために、配信をバッチ処理したり、遅らせたりできます。
| 機能 | レガシー(AndroidConfig v1) |
新規(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 Cloud Messaging 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 は Google の公開 Maven リポジトリではなく、ローカルの 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 メッセージが表示されます。
mutable_content: true を含む RemoteNotification が到着すると、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)
1 つの受信プッシュに対して複数の通知を投稿する必要がある場合や、新しい通知を表示する前に古い通知をキャンセルする必要がある場合は、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 プラットフォーム内に留まります。
- 変更可能な通知を配信する: サーバーは、
mutable_content: true、dataの暗号化されたペイロード、一般的な暗号化されていないバックアップnotificationを含むRemoteNotificationを送信します。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 メッセージの通知を表示することが想定されています。
すべてのアプリケーションは、バックグラウンドで実行中に RemoteNotification トラフィックの最大 25% を抑制できます。アプリの抑制率が 25% を超えると、GMS Core は remote_notification.notification ペイロードからレンダリングされたフォールバック通知を自動的にレンダリングして投稿します。
アプリがフォアグラウンドでアクティブなときに実行される抑制は、このしきい値にカウントされません。無制限のバックグラウンド使用権限が付与されているアプリケーションも、バックグラウンド抑制制限の対象外となります。