Con la FCM AndroidConfigV2, puedes enviar mensajes basados en intents a dispositivos Android con una entrega de notificaciones oportuna y una API simplificada.
En esta guía, se explica cómo migrar las solicitudes de envío de tu backend de AndroidConfig
a AndroidConfigV2 y cómo actualizar los clientes de tu aplicación para Android
desde el manejo heredado de onMessageReceived a las nuevas devoluciones de llamada del cliente de la versión 2
onNotificationReceived y onBackgroundSyncReceived.
Novedades de AndroidConfigV2
La API de AndroidConfigV2 de FCM simplifica la experiencia de los desarrolladores, ya que presenta dos tipos de mensajes:
RemoteNotification: Se recomienda para todos los mensajes de FCM que muestran una notificación urgente y urgente visible para el usuario. Estos mensajes omiten las medidas de ahorro de batería y se entregan sin demora. En el dispositivo, el SDK de FCM y los Servicios de Google Play se encargan de publicar la notificación en elNotificationManagerde Android.BackgroundSync: Son mensajes de datos no urgentes destinados a la sincronización en segundo plano y las actualizaciones del estado de la app. La entrega se puede realizar por lotes o retrasarse para optimizar la duración de la batería.
| Función | Heredada (AndroidConfig v1) |
Nuevo (AndroidConfigV2) |
|---|---|---|
| Campo de configuración | message.android |
message.android_v2 |
| Definición de prioridad | priority: "high" o priority: "normal" explícito |
Implícito por el tipo de unión (remote_notification para alertas urgentes en comparación con background_sync para la sincronización no urgente) |
| Publicación de notificaciones | La app llama a NotificationManager.notify() de forma manual |
El SDK de FCM y los Servicios de Google para dispositivos móviles publican directamente o con NotificationResponse |
| Devoluciones de llamada del cliente | • onMessageReceived(RemoteMessage)• onDeletedMessages() |
• onNotificationReceived(RemoteMessage)• onBackgroundSyncReceived(RemoteMessage)• onDeletedMessages() |
| Contracción | Varía; se requiere un parámetro de configuración explícito | Ambos tipos de mensajes pueden ser contraíbles o no contraíbles (no contraíbles de forma predeterminada). |
Autoriza solicitudes de envío de AndroidConfigV2
Puedes seguir usando los tokens de acceso de OAuth 2.0 derivados de tu cuenta de servicio de Firebase
con las credenciales predeterminadas de la aplicación de Google o el SDK de Admin,
y enviar solicitudes POST al extremo messages:send de HTTP v1.
Si no usas tu cuenta de servicio de Firebase, asegúrate de asignar tu cuenta dedicada al rol de administrador de la API de Firebase Cloud Messaging (roles/firebase.messagingAdmin)
y solicita el permiso de OAuth 2.0
https://www.googleapis.com/auth/firebase.messaging cuando crees tokens de acceso:
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
Actualiza las solicitudes de envío del servidor (REST)
Para enviar una solicitud AndroidConfigV2 con la API de REST, reemplaza el objeto android
en el cuerpo de la solicitud por android_v2. En android_v2, especifica
los parámetros comunes (como ttl, collapse_key, data y
restricted_package_name) y proporciona uno de los siguientes campos de unión:
remote_notification o background_sync.
Envía un mensaje RemoteNotification
Para enviar una notificación urgente para el usuario, incluye el objeto remote_notification
y su carga útil notification recomendada. De forma predeterminada, mutable_content
se establece en falso. Los Servicios de Google para dispositivos móviles renderizan y publican de inmediato la notificación en la bandeja del sistema sin ejecutar el código de la app en segundo plano.
Ejemplo completo de JSON de solicitud HTTP (notificación renderizada automáticamente)
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
}
}
}
}
}
Envía una RemoteNotification con contenido mutable
Si tu aplicación necesita modificar la notificación en el dispositivo antes de que se
muestre, establece mutable_content: true dentro de remote_notification. Esto
le indica a GMS Core que se vincule a tu aplicación cliente y que invoque
onNotificationReceived(). Esto es útil cuando quieres desencriptar una
carga útil encriptada de extremo a extremo, adjuntar avatares de usuario o
localizar cadenas.
Asegúrate de incluir un objeto notification dentro de remote_notification, incluso cuando mutable_content sea true. Los Servicios de GMS usan este objeto notification como la notificación de resguardo si se agota el tiempo de espera de la devolución de llamada del cliente o se superan los límites de supresión.
Si migras desde mensajes de datos heredados de la versión 1 y quieres que FCM
entregue la carga útil a instalaciones de clientes de la versión 1 más antiguas como un mensaje de datos puro, establece
use_as_v1_data_message: true dentro de remote_notification.
Ejemplo completo de JSON de solicitud 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...",
"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
}
}
}
}
}
Envía un mensaje de BackgroundSync
Para enviar un mensaje no urgente para la sincronización de datos en segundo plano, las actualizaciones de estado silenciosas o la actualización de un widget o una insignia de la app, usa el objeto background_sync.
No uses estos mensajes para publicar
notificaciones visibles para el usuario, ya que se pueden agrupar por lotes o retrasar para optimizar
la duración de batería del dispositivo.
Ejemplo completo de JSON de solicitud 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...",
"data": {
"score": "FETCH_UPDATES",
"sync_action": "FETCH_UPDATES"
},
"android_v2": {
"ttl": "86400s",
"collapse_key": "app_state_sync",
"background_sync": {}
}
}
}
Actualiza las devoluciones de llamada del cliente de Android
Para recibir mensajes de AndroidConfigV2 en Android, actualiza tu app para que use el
SDK de firebase-messaging más reciente. Actualiza tu servicio extendiendo
FirebaseMessagingService con la implementación de onNotificationReceived() y
onBackgroundSyncReceived().
Instala el SDK del EAP
Durante el EAP, el SDK de firebase-messaging v2 se distribuye como un archivo de repositorio de Maven local, en lugar de hacerlo a través del repositorio público de Maven de Google.
Agrega el directorio
m2repositoryque contienefirebase-messaging:26.1.0-eap01al directorio raíz de tu proyecto de Android (<project-root>/m2repository) con una de las siguientes opciones:- Opción A: Descarga el archivo compilado previamente: Descarga
FirebaseMessaging_26.1.0-eap01.zip
y extrae el directorio
m2repositoryen el directorio raíz de tu proyecto de Android (<project-root>/m2repository). Opción B: Compila desde GitHub con Gradle: Clona la rama
feature/fcm-android-config-v2-eapdefirebase/firebase-android-sdk, compila el repositorio de Maven local y copia el directoriobuild/m2repositorygenerado en la raíz de tu proyecto de 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
- Opción A: Descarga el archivo compilado previamente: Descarga
FirebaseMessaging_26.1.0-eap01.zip
y extrae el directorio
En el archivo
settings.gradle.kts(osettings.gradle) de nivel de proyecto, agrega el directorio localm2repositorya la parte superior del bloquerepositories, por encima degoogle():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() } }En el archivo
app/build.gradle.kts(oapp/build.gradle) a nivel del módulo, actualiza la dependencia defirebase-messaginga26.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' }Sincroniza tu proyecto con archivos de Gradle.
Controla RemoteNotifications con onNotificationReceived
Con AndroidConfigV2, se muestran los mensajes de RemoteNotification,
a menos que mutable_content se establezca como verdadero o que se silencien de forma explícita en
onNotificationReceived().
Cuando llega un RemoteNotification con mutable_content: true, GMS Core se vincula
a tu aplicación y llama a onNotificationReceived(). Tu método debe
devolver un NotificationResponse en un plazo de 20 segundos.
Cómo devolver una notificación modificada
El objeto Notification que pasas a NotificationResponse.create reemplaza las propiedades de carga útil de resguardo remote_notification.notification del servidor definidas en la solicitud de envío. Para conservar los valores de la solicitud de envío, léelos de
message.notification (message.getNotification() en Java) mientras aplicas
las modificaciones integrado en el dispositivo:
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());
}
}
Cómo suprimir una notificación
Si el usuario tiene la pantalla o el chat pertinentes activos en este momento, puedes suprimir la notificación devolviendo 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());
}
Transmite notificaciones o cancela alertas más antiguas (FcmNotificationManager)
Si necesitas publicar varias notificaciones para un solo mensaje push entrante o cancelar
una notificación inactiva antes de mostrar una nueva, usa 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();
}
Controla los mensajes de BackgroundSync con onBackgroundSyncReceived
Para procesar mensajes de BackgroundSync en Android, usa
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.
}
Controla las eliminaciones de mensajes pendientes con onDeletedMessages
En algunas situaciones, como cuando un dispositivo no se conectó a FCM durante
un período prolongado o cuando la cola del servidor está llena, FCM puede borrar
los mensajes pendientes antes de la entrega. En estos casos, anula 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();
}
Cómo migrar apps específicas
Envía notificaciones con encriptación de extremo a extremo (E2EE)
Cuando se entrega una notificación encriptada de extremo a extremo con un
RemoteNotification, el contenido de la notificación
desencriptada permanece dentro de tu app y de la plataforma de Android:
- Envía una notificación mutable:
Tu servidor envía un
RemoteNotificationconmutable_content: true, la carga útil encriptada endatay una copia de seguridad genérica sin encriptarnotification. Los Servicios de Google Play entregan el mensaje encriptado al SDK de FCM de código abierto dentro de tu app. - Desencripta y devuelve la notificación: El SDK de FCM invoca a
onNotificationReceived(). Tu app desencripta la carga útil de forma local, compila elNotificationde Android desencriptado final y lo pasa de vuelta al SDK de código abierto de FCM conNotificationResponseoFcmNotificationManager. - Publica en la plataforma y genera informes de metadatos: El SDK de código abierto de FCM publica la notificación desencriptada directamente en la API de
NotificationManagerde la plataforma de Android y envía solo los metadatos de la notificación, como los IDs de notificación y las marcas de tiempo, de vuelta a los Servicios de Google Play para la observabilidad de la entrega. El contenido desencriptado nunca se envía a GMS Core. - Publica una notificación de copia de seguridad si es necesario: Solo si tu app no responde
en el tiempo de espera de 20 segundos o supera los límites de supresión en segundo plano,
los Servicios de GMS publican la
notificationde copia de seguridad genérica directamente en la plataforma de Android.

Información sobre la supresión y los tiempos de espera de las notificaciones
Para mantener una entrega confiable en todo el ecosistema Android, GMS Core aplica tiempos de espera de procesamiento y límites de supresión de notificaciones cuando se manejan mensajes de RemoteNotification:
Tiempo de espera de procesamiento
Cuando mutable_content se establece en true, tu método onNotificationReceived() debe devolver un NotificationResponse en un plazo de 20 segundos. Si
la ejecución supera este umbral, se cancela la devolución de llamada y los Servicios de Google Play
publican automáticamente una notificación de resguardo renderizada a partir de la
carga útil de remote_notification.notification.
Tasa de supresión de notificaciones
Dado que los mensajes de RemoteNotification omiten las restricciones de Doze para alertar a los usuarios
de inmediato y se entregan sin demora, se espera que las aplicaciones
muestren notificaciones de los mensajes de RemoteNotification recibidos.
Cada aplicación puede suprimir hasta un 25% de su tráfico de RemoteNotification mientras se ejecuta en segundo plano. Si la tasa de supresión de una aplicación supera el 25%, los Servicios de Google para dispositivos móviles renderizan y publican automáticamente una notificación de resguardo renderizada a partir de la carga útil de remote_notification.notification.
Las eliminaciones que se realizan cuando la aplicación está activa en primer plano no se tienen en cuenta para este umbral. Las aplicaciones a las que se les otorgan permisos de uso en segundo plano sin restricciones también están exentas de los límites de supresión en segundo plano.