Esegui la migrazione dall'API HTTP v1 di FCM ad AndroidConfigV2

Utilizzando FCM AndroidConfigV2, puoi inviare messaggi basati sugli intent ai dispositivi Android con una consegna tempestiva delle notifiche e un'API semplificata.

Questa guida spiega come eseguire la migrazione delle richieste di invio del backend da AndroidConfig a AndroidConfigV2 e come aggiornare i client delle app per Android dalla gestione precedente di onMessageReceived ai nuovi callback client v2 onNotificationReceived e onBackgroundSyncReceived.

Novità di AndroidConfigV2

L'API FCM AndroidConfigV2 semplifica l'esperienza degli sviluppatori introducendo due tipi di messaggi:

  • RemoteNotification: consigliato per tutti i messaggi FCM che mostrano una notifica urgente e sensibile al fattore tempo visibile all'utente. Questi messaggi bypassano qualsiasi misura di risparmio della batteria e vengono recapitati senza ritardi. Sul dispositivo, l'SDK FCM e Google Play Services si occupano della pubblicazione della notifica nel NotificationManager di Android.
  • BackgroundSync: messaggi di dati non urgenti destinati alla sincronizzazione in background e agli aggiornamenti dello stato dell'app. La consegna può essere raggruppata o ritardata per ottimizzare la durata della batteria.
Funzionalità Legacy (AndroidConfig v1) Nuovo (AndroidConfigV2)
Campo di configurazione message.android message.android_v2
Definizione della priorità priority: "high" o priority: "normal" esplicito Implicito dal tipo di unione (remote_notification per gli avvisi urgenti rispetto a background_sync per la sincronizzazione non urgente)
Pubblicazione di notifiche L'app chiama manualmente NotificationManager.notify() L'SDK FCM e GMS Core pubblicano direttamente o utilizzando NotificationResponse
Callback client • onMessageReceived(RemoteMessage)
• onDeletedMessages()
• onNotificationReceived(RemoteMessage)
• onBackgroundSyncReceived(RemoteMessage)
• onDeletedMessages()
Comprimibilità Variabile; è richiesta un'impostazione esplicita Entrambi i tipi di messaggi possono essere comprimibili o non comprimibili (non comprimibili per impostazione predefinita)

Autorizza le richieste di invio di AndroidConfigV2

Puoi continuare a utilizzare i token di accesso OAuth 2.0 derivati dal tuo service account Firebase utilizzando le Credenziali predefinite dell'applicazione Google o l'SDK Admin e inviare richieste POST all'endpoint HTTP v1 messages:send.

Se non utilizzi il service account Firebase, assicurati di assegnare il tuo account dedicato al ruolo Firebase Cloud Messaging API Admin (roles/firebase.messagingAdmin) e richiedi l'ambito OAuth 2.0 https://www.googleapis.com/auth/firebase.messaging quando generi i token di accesso:

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

Aggiorna le richieste di invio del server (REST)

Per inviare una richiesta AndroidConfigV2 utilizzando l'API REST, sostituisci l'oggetto android nel corpo della richiesta con android_v2. All'interno di android_v2, specifica i parametri comuni (come ttl, collapse_key, data e restricted_package_name) e fornisci uno dei seguenti campi di unione: remote_notification o background_sync.

Invia un messaggio RemoteNotification

Per inviare una notifica urgente rivolta agli utenti, includi l'oggetto remote_notification e il relativo payload notification consigliato. Per impostazione predefinita, mutable_content è impostato su false. GMS Core esegue immediatamente il rendering e pubblica la notifica nella barra delle applicazioni senza eseguire il codice dell'app in background.

Esempio JSON di richiesta HTTP completa (notifica con rendering automatico)

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
        }
      }
    }
  }
}

Invia una RemoteNotification con contenuti modificabili

Se la tua applicazione deve modificare la notifica sul dispositivo prima che venga visualizzata, imposta mutable_content: true all'interno di remote_notification. In questo modo, GMS Core viene associato alla tua applicazione client e richiama onNotificationReceived(). Questo è utile quando vuoi decriptare un payload con crittografia end-to-end, allegare avatar utente o localizzare stringhe.

Assicurati di includere un oggetto notification all'interno di remote_notification anche quando mutable_content è true. GMS Core utilizza questo oggetto notification come notifica di riserva se il callback del client scade o supera i limiti di soppressione.

Se stai eseguendo la migrazione dai messaggi di dati v1 legacy e vuoi che FCM invii il payload alle installazioni client v1 precedenti come messaggio di dati puro, imposta use_as_v1_data_message: true all'interno di remote_notification.

Esempio JSON di richiesta HTTP completa

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
        }
      }
    }
  }
}

Invia un messaggio BackgroundSync

Per inviare un messaggio non urgente per la sincronizzazione dei dati in background, gli aggiornamenti dello stato silenzioso o l'aggiornamento di un badge o di un widget dell'app, utilizza l'oggetto background_sync. Non utilizzare questi messaggi per pubblicare notifiche visibili agli utenti, in quanto possono essere raggruppati o ritardati per ottimizzare la durata della batteria del dispositivo.

Esempio JSON di richiesta HTTP completa

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": {}
    }
  }
}

Aggiorna i callback del client Android

Per ricevere messaggi AndroidConfigV2 su Android, esegui l'upgrade della tua app in modo che utilizzi l'SDK firebase-messaging più recente. Aggiorna il servizio estendendo FirebaseMessagingService implementando onNotificationReceived() e onBackgroundSyncReceived().

Installa l'SDK EAP

Durante l'EAP, l'SDK firebase-messaging v2 viene distribuito come archivio del repository Maven locale anziché tramite il repository Maven pubblico di Google.

  1. Aggiungi la directory m2repository contenente firebase-messaging:26.1.0-eap01 alla directory root del tuo progetto Android (<project-root>/m2repository) utilizzando una delle seguenti opzioni:

    1. Opzione A: scarica l'archivio predefinito: scarica FirebaseMessaging_26.1.0-eap01.zip ed estrai la directory m2repository nella directory root del tuo progetto Android (<project-root>/m2repository).
    2. Opzione B: crea da GitHub con Gradle: clona il branch feature/fcm-android-config-v2-eap di firebase/firebase-android-sdk, crea il repository Maven locale e copia la directory build/m2repository generata nella directory principale del progetto 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
      
  2. Nel file settings.gradle.kts (o settings.gradle) a livello di progetto, aggiungi la directory m2repository locale all'inizio del blocco repositories, sopra 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()
        }
    }
    
  3. Nel file app/build.gradle.kts (o app/build.gradle) a livello di modulo, aggiorna la dipendenza firebase-messaging in 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'
    }
    
  4. Sincronizza il progetto con i file Gradle.

Gestisci le notifiche remote con onNotificationReceived

Con AndroidConfigV2, i messaggi RemoteNotification vengono visualizzati, a meno che mutable_content non sia impostato su true o non siano esplicitamente disattivati in onNotificationReceived().

Quando arriva un RemoteNotification con mutable_content: true, GMS Core si associa alla tua applicazione e chiama onNotificationReceived(). Il metodo deve restituire un NotificationResponse entro 20 secondi.

Restituisci una notifica modificata

L'oggetto Notification che passi a NotificationResponse.create sostituisce le proprietà del payload di riserva remote_notification.notification del server definite nella richiesta di invio. Per conservare i valori della richiesta di invio, leggili da message.notification (message.getNotification() in Java) mentre applichi le modifiche on-device:

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());
    }
}

Elimina una notifica

Se l'utente ha la schermata o la chat pertinente attiva in questo momento, puoi sopprimere la notifica restituendo 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());
}

Notifiche in streaming o annullamento degli avvisi meno recenti (FcmNotificationManager)

Se devi pubblicare più notifiche per una singola notifica push in arrivo o annullare una notifica obsoleta prima di visualizzarne una nuova, utilizza 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();
}

Gestisci i messaggi BackgroundSync utilizzando onBackgroundSyncReceived

Per elaborare i messaggi BackgroundSync su Android, utilizza 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.
}

Gestisci le eliminazioni dei messaggi in attesa utilizzando onDeletedMessages

In alcune situazioni, ad esempio quando un dispositivo non si connette a FCM per un periodo di tempo prolungato o quando la coda del server è piena, FCM potrebbe eliminare i messaggi in attesa prima della consegna. In questi casi, esegui l'override di 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();
}

Esegui la migrazione di app specifiche

Inviare notifiche con crittografia end-to-end (E2EE)

Quando invii una notifica con crittografia end-to-end utilizzando un RemoteNotification, i contenuti della notifica decriptati rimangono all'interno della tua app e della piattaforma Android:

  1. Invia una notifica modificabile: il tuo server invia un RemoteNotification con mutable_content: true, il payload criptato in data e un backup generico non criptato notification. GMS Core invia il messaggio criptato all'SDK FCM open source all'interno della tua app.
  2. Decripta e restituisci la notifica: l'SDK FCM richiama onNotificationReceived(). La tua app decripta il payload localmente, crea l'Android Notification decriptato finale e lo restituisce all'SDK FCM open source utilizzando NotificationResponse o FcmNotificationManager.
  3. Pubblicazione sulla piattaforma e segnalazione dei metadati: l'SDK FCM open source pubblica la notifica decriptata direttamente nell'API NotificationManager della piattaforma Android e invia solo i metadati della notifica, come gli ID e i timestamp delle notifiche, a GMS Core per l'osservabilità della distribuzione. I contenuti decriptati non vengono mai inviati a GMS Core.
  4. Pubblica una notifica di backup, se necessario: solo se l'app non risponde entro il timeout di 20 secondi o supera i limiti di soppressione in background, GMS Core pubblica il backup generico notification direttamente sulla piattaforma Android.

Diagramma dell'architettura che mostra il flusso di invio delle notifiche con crittografia end-to-end in 4 passaggi tra GMS Core, l'SDK FCM open source, la tua app e l'API NotificationManager della piattaforma Android.

Informazioni sulla soppressione e sui timeout delle notifiche

Per mantenere una distribuzione affidabile nell'ecosistema Android, GMS Core applica timeout di elaborazione e limiti di soppressione delle notifiche durante la gestione dei messaggi RemoteNotification:

Timeout di elaborazione

Quando mutable_content è impostato su true, il metodo onNotificationReceived() deve restituire un NotificationResponse entro 20 secondi. Se l'esecuzione supera questa soglia, il callback viene annullato e GMS Core pubblica automaticamente una notifica di riserva visualizzata dal payload remote_notification.notification.

Tasso di soppressione delle notifiche

Poiché i messaggi RemoteNotification bypassano le limitazioni di Doze per avvisare immediatamente gli utenti e vengono recapitati senza ritardi, le applicazioni devono mostrare le notifiche per i messaggi RemoteNotification ricevuti.

Ogni applicazione può sopprimere fino al 25% del traffico RemoteNotification durante l'esecuzione in background. Se il tasso di soppressione di un'applicazione supera il 25%, GMS Core esegue automaticamente il rendering e pubblica una notifica di riserva dal payload remote_notification.notification.

Le soppressioni eseguite quando l'applicazione è attiva in primo piano non vengono conteggiate ai fini di questa soglia. Anche le applicazioni a cui sono state concesse autorizzazioni di utilizzo in background senza limitazioni sono esenti dai limiti di soppressione in background.