С помощью FCM AndroidConfigV2 вы можете отправлять сообщения на устройства Android, используя упрощенный API и своевременную доставку уведомлений.
В этом руководстве рассказывается, как перенести запросы на отправку с сервера из AndroidConfig в AndroidConfigV2 и как обновить клиенты приложений Android, чтобы вместо устаревшей обработки onMessageReceived использовать новые обратные вызовы клиента версии 2 – onNotificationReceived и onBackgroundSyncReceived.
Что нового в AndroidConfigV2
API FCM AndroidConfigV2 упрощает работу разработчиков, предлагая два типа сообщений:
RemoteNotification– рекомендуется для всех сообщений FCM, которые показывают срочное, ограниченное по времени уведомление, видимое пользователю. Такие сообщения доставляются без задержек, даже если включен режим энергосбережения. На устройстве SDK FCM и сервисы Google Play отвечают за публикацию уведомления вNotificationManagerAndroid.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
Вы можете по-прежнему использовать токены доступа OAuth 2.0, полученные из сервисного аккаунта Firebase с помощью Application Default Credentials или Admin SDK, и отправлять запросы POST на конечную точку HTTP v1 messages:send.
Если вы не используете сервисный аккаунт Firebase, назначьте своему аккаунту роль Firebase Cloud Messaging API Admin (roles/firebase.messagingAdmin) и запросите область действия OAuth 2.0 https://www.googleapis.com/auth/firebase.messaging при создании токенов доступа.
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)
Чтобы отправить запрос AndroidConfigV2 с помощью REST API, замените объект 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 сразу же отрисовывает и публикует уведомление в области уведомлений, не выполняя фоновый код приложения.
Полный пример JSON-кода HTTP-запроса (автоматически отрисованное уведомление)
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 с изменяемым контентом.
Если вашему приложению нужно изменить уведомление на устройстве до его показа, задайте mutable_content: true внутри remote_notification. Это указывает GMS Core на необходимость привязки к вашему клиентскому приложению и вызова onNotificationReceived(). Это полезно, когда нужно расшифровать полезную нагрузку со сквозным шифрованием, прикрепить аватары пользователей или локализовать строки.
Обязательно включите объект notification в remote_notification, даже если mutable_content имеет значение true. GMS Core использует этот объект notification в качестве резервного уведомления, если время ожидания обратного вызова клиента истекло или превышены ограничения на подавление.
Если вы переходите с устаревших сообщений с данными версии 1 и хотите, чтобы FCM доставлял полезную нагрузку в старые клиентские установки версии 1 в виде чистого сообщения с данными, установите use_as_v1_data_message: true внутри remote_notification.
Полный пример 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
Чтобы получать сообщения AndroidConfigV2 на устройствах Android, обновите приложение, чтобы использовать последнюю версию SDK firebase-messaging. Обновите сервис, расширяющий FirebaseMessagingService, реализовав onNotificationReceived() и onBackgroundSyncReceived().
Установите SDK для программы раннего доступа
В период действия программы раннего доступа SDK firebase-messaging версии 2 распространяется как локальный архив репозитория Maven, а не через общедоступный репозиторий Google Maven.
Добавьте каталог
m2repository, содержащийfirebase-messaging:26.1.0-eap01, в корневой каталог проекта для Android (<project-root>/m2repository) одним из следующих способов:- Вариант А. Скачайте готовый архив. Скачайте файл FirebaseMessaging_26.1.0-eap01.zip и распакуйте каталог
m2repositoryв корневой каталог проекта Android (<project-root>/m2repository). Вариант Б. Сборка из GitHub с помощью Gradle. Клонируйте ветку
feature/fcm-android-config-v2-eapизfirebase/firebase-android-sdk, создайте локальный репозиторий 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
- Вариант А. Скачайте готовый архив. Скачайте файл 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.
Обработка RemoteNotifications с помощью onNotificationReceived
Если задано значение AndroidConfigV2, сообщения RemoteNotification показываются, если для mutable_content не задано значение True или они не отключены в onNotificationReceived().
Когда поступает RemoteNotification с mutable_content: true, GMS Core связывается с вашим приложением и вызывает onNotificationReceived(). Ваш метод должен возвращать NotificationResponse в течение 20 секунд.
Как вернуть измененное уведомление
Объект Notification, который вы передаете в NotificationResponse.create, заменяет свойства резервной полезной нагрузки remote_notification.notification сервера, определенные в запросе на отправку. Чтобы сохранить значения из запроса на отправку, прочитайте их из message.notification (message.getNotification() в Java), применяя изменения на устройстве:
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)
Если вам нужно опубликовать несколько уведомлений для одного входящего push-уведомления или отменить устаревшее уведомление перед показом нового, используйте 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();
}
Обработка сообщений BackgroundSync с помощью onBackgroundSyncReceived
Чтобы обрабатывать сообщения BackgroundSync на Android, используйте 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();
}
Как перенести данные определенных приложений
Доставка уведомлений со сквозным шифрованием
При доставке уведомления со сквозным шифрованием с помощью RemoteNotification расшифрованный контент уведомления остается в приложении и на платформе Android.
- Доставка изменяемого уведомления.
Ваш сервер отправляет
RemoteNotificationсmutable_content: true, зашифрованную полезную нагрузку вdataи общую незашифрованную резервную копиюnotification. GMS Core передает зашифрованное сообщение в SDK FCM с открытым исходным кодом, который находится в вашем приложении. - Расшифровка и возврат уведомления. SDK FCM вызывает
onNotificationReceived(). Приложение расшифровывает полезную нагрузку локально, создает окончательный расшифрованный объектNotificationдля Android и передает его обратно в SDK FCM с открытым исходным кодом, используяNotificationResponseилиFcmNotificationManager. - Публикация на платформе и передача метаданных. SDK FCM с открытым исходным кодом публикует расшифрованное уведомление напрямую в API
NotificationManagerплатформы Android и отправляет в GMS Core только метаданные уведомления, например идентификаторы и временные метки, чтобы можно было отслеживать доставку. Расшифрованный контент никогда не отправляется в GMS Core. - Показ резервного уведомления (при необходимости). Если приложение не отвечает в течение 20 секунд или превышает ограничения на подавление фоновых уведомлений, GMS Core отправляет стандартное резервное уведомление
notificationнапрямую на платформу Android.

Как работает подавление уведомлений и тайм-ауты
Чтобы обеспечить надежную доставку в экосистеме Android, GMS Core применяет тайм-ауты обработки и ограничения на подавление уведомлений при обработке сообщений RemoteNotification:
Время обработки истекло
Если для параметра mutable_content задано значение true, метод onNotificationReceived() должен возвращать NotificationResponse в течение 20 секунд. Если выполнение превышает это пороговое значение, обратный вызов отменяется, а GMS Core автоматически публикует резервное уведомление, созданное на основе полезной нагрузки remote_notification.notification.
Доля заблокированных уведомлений
Поскольку сообщения RemoteNotification обходят ограничения спящего режима, чтобы немедленно оповещать пользователей, и доставляются без задержки, приложения должны показывать уведомления о полученных сообщениях RemoteNotification.
Каждому приложению разрешено подавлять до 25% трафика RemoteNotification при работе в фоновом режиме. Если доля подавленных уведомлений превышает 25%, GMS Core автоматически создает и публикует резервное уведомление на основе полезной нагрузки remote_notification.notification.
Блокировки, выполненные, когда приложение активно на переднем плане, не учитываются. Приложения, которым предоставлены разрешения на неограниченное использование в фоновом режиме, также освобождаются от ограничений на подавление фонового режима.