Envoyer des messages à plusieurs appareils

Pour cibler un message sur plusieurs appareils, utilisez la messagerie par sujet. Cette fonctionnalité vous permet d'envoyer un message à plusieurs appareils qui ont activé un thème particulier.

Ce tutoriel explique comment envoyer des messages de discussion à partir de votre serveur d'application à l'aide de Admin SDK ou de l'API REST pour FCM, et comment les recevoir et les gérer dans une application Android. Nous aborderons la gestion des messages pour les applications en arrière-plan et en premier plan. Toutes les étapes à suivre sont détaillées, de la configuration à la validation.

Configurez le SDK

Cette section peut couvrir des étapes que vous avez déjà effectuées si vous avez configuré une application cliente Android pour FCM ou suivi la procédure pour envoyer votre premier message.

Avant de commencer

  • Installez ou mettez à jour Android Studio vers la dernière version.

  • Assurez-vous que votre projet répond à ces exigences (notez que certains produits peuvent avoir des exigences plus strictes):

    • Cible le niveau d'API 21 (Lollipop) ou version ultérieure
    • Utilise Android 5.0 ou version ultérieure
    • Utilise Jetpack (AndroidX), ce qui implique de respecter les exigences de version suivantes :
      • com.android.tools.build:gradle v7.3.0 ou version ultérieure
      • compileSdkVersion 28 ou version ultérieure
  • Configurez un appareil physique ou utilisez un émulateur pour exécuter votre application.
    Notez que les SDK Firebase dépendant des services Google Play nécessitent que les services Google Play soient installés sur l'appareil ou l'émulateur.

  • Connectez-vous à Firebase avec votre compte Google.

Si vous ne disposez pas encore d'un projet Android et que vous souhaitez simplement essayer un produit Firebase, vous pouvez télécharger l'un de nos exemples de démarrage rapide.

Créer un projet Firebase

Avant de pouvoir ajouter Firebase à votre application Android, vous devez créer un projet Firebase pour vous y connecter. Pour en savoir plus sur les projets Firebase, consultez la page Comprendre les projets Firebase.

Enregistrer votre application auprès de Firebase

Pour utiliser Firebase dans votre application Android, vous devez enregistrer votre application auprès de votre projet Firebase. L'enregistrement de votre application est souvent appelé "ajout" de votre application à votre projet.

  1. Accédez à la console Firebase.

  2. Au centre de la page de présentation du projet, cliquez sur l'icône Android () ou sur Ajouter une application pour lancer le processus de configuration.

  3. Saisissez le nom du package de votre application dans le champ Nom du package Android.

  4. (Facultatif) Saisissez d'autres informations sur l'application : Pseudo de l'application et Certificat de signature de débogage SHA-1.

  5. Cliquez sur Enregistrer l'application.

Ajouter un fichier de configuration Firebase

  1. Téléchargez, puis ajoutez le fichier de configuration Firebase Android (google-services.json) à votre application:

    1. Cliquez sur Télécharger google-services.json pour obtenir votre fichier de configuration Firebase Android.

    2. Déplacez votre fichier de configuration dans le répertoire racine du module (au niveau de l'application) de votre application.

  2. Pour rendre les valeurs de votre fichier de configuration google-services.json accessibles aux SDK Firebase, vous devez disposer du plug-in Gradle des services Google (google-services).

    1. Dans votre fichier Gradle au niveau racine (au niveau du projet) (<project>/build.gradle.kts ou <project>/build.gradle), ajoutez le plug-in des services Google en tant que dépendance:

      Kotlin

      plugins {
        id("com.android.application") version "7.3.0" apply false
        // ...
      
        // Add the dependency for the Google services Gradle plugin
        id("com.google.gms.google-services") version "4.4.2" apply false
      }
      

      Groovy

      plugins {
        id 'com.android.application' version '7.3.0' apply false
        // ...
      
        // Add the dependency for the Google services Gradle plugin
        id 'com.google.gms.google-services' version '4.4.2' apply false
      }
      
    2. Dans le fichier Gradle de votre module (au niveau de l'application) (généralement <project>/<app-module>/build.gradle.kts ou <project>/<app-module>/build.gradle), ajoutez le plug-in des services Google:

      Kotlin

      plugins {
        id("com.android.application")
      
        // Add the Google services Gradle plugin
        id("com.google.gms.google-services")
        // ...
      }
      

      Groovy

      plugins {
        id 'com.android.application'
      
        // Add the Google services Gradle plugin
        id 'com.google.gms.google-services'
        // ...
      }
      

Ajouter des SDK Firebase à votre application

  1. Dans le fichier Gradle de votre module (au niveau de l'application) (généralement <project>/<app-module>/build.gradle.kts ou <project>/<app-module>/build.gradle), ajoutez la dépendance pour la bibliothèque Firebase Cloud Messaging pour Android. Nous vous recommandons d'utiliser Firebase Android BoM pour contrôler le contrôle des versions de la bibliothèque.

    Pour une expérience optimale avec Firebase Cloud Messaging, nous vous recommandons d'activer Google Analytics dans votre projet Firebase et d'ajouter le SDK Firebase pour Google Analytics à votre application.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.6.0"))
    
        // Add the dependencies for the Firebase Cloud Messaging and Analytics libraries
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-messaging")
        implementation("com.google.firebase:firebase-analytics")
    }
    

    En utilisant Firebase Android BoM, votre application utilisera toujours des versions compatibles des bibliothèques Firebase Android.

    (Alternative) Ajoutez des dépendances de bibliothèque Firebase sans utiliser BoM.

    Si vous choisissez de ne pas utiliser Firebase BoM, vous devez spécifier chaque version de la bibliothèque Firebase dans sa ligne de dépendance.

    Notez que si vous utilisez plusieurs bibliothèques Firebase dans votre application, nous vous recommandons vivement d'utiliser BoM pour gérer les versions de la bibliothèque, ce qui garantit que toutes les versions sont compatibles.

    dependencies {
        // Add the dependencies for the Firebase Cloud Messaging and Analytics libraries
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-messaging:24.1.0")
        implementation("com.google.firebase:firebase-analytics:22.1.2")
    }
    
    Vous recherchez un module de bibliothèque spécifique à Kotlin ? À partir d'octobre 2023 (Firebase BoM 32.5.0), les développeurs Kotlin et Java peuvent dépendre du module de bibliothèque principal (pour en savoir plus, consultez les questions fréquentes sur cette initiative).

  2. Synchronisez votre projet Android avec les fichiers Gradle.

Abonner l'application cliente à un sujet

Les applications clientes peuvent s'abonner à n'importe quel sujet existant ou en créer un. Lorsqu'une application cliente s'abonne à un nouveau nom de topic (qui n'existe pas encore pour votre projet Firebase), un nouveau topic de ce nom est créé dans FCM et tout client peut ensuite s'y abonner.

Pour s'abonner à un sujet, l'application cliente appelle Firebase Cloud Messaging subscribeToTopic() avec le nom du sujet FCM. Cette méthode renvoie un Task, qui peut être utilisé par un écouteur de fin pour déterminer si l'abonnement a réussi:

Kotlin+KTX

Firebase.messaging.subscribeToTopic("weather")
    .addOnCompleteListener { task ->
        var msg = "Subscribed"
        if (!task.isSuccessful) {
            msg = "Subscribe failed"
        }
        Log.d(TAG, msg)
        Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
    }

Java

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                String msg = "Subscribed";
                if (!task.isSuccessful()) {
                    msg = "Subscribe failed";
                }
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Pour se désabonner, l'application cliente appelle Firebase Cloud Messaging unsubscribeFromTopic() avec le nom du sujet.

Recevoir et gérer les messages de discussion

FCM distribue les messages de sujet de la même manière que les autres messages en aval.

Pour recevoir des messages, utilisez un service qui étend FirebaseMessagingService. Votre service doit remplacer les rappels onMessageReceived et onDeletedMessages.

La période de traitement d'un message peut être inférieure à 20 secondes en fonction des retards subis avant l'appel de onMessageReceived, y compris les retards de l'OS, le temps de démarrage de l'application, le thread principal bloqué par d'autres opérations ou les appels onMessageReceived précédents prenant trop de temps. Passé ce délai, divers comportements de l'OS, tels que l'arrêt du processus d'Android ou les limites d'exécution en arrière-plan d'Android O, peuvent vous empêcher de terminer votre travail.

onMessageReceived est fourni pour la plupart des types de messages, à quelques exceptions près:

  • Messages de notification envoyés lorsque votre application est en arrière-plan Dans ce cas, la notification est envoyée à la barre d'état système de l'appareil. Lorsqu'un utilisateur appuie sur une notification, le lanceur d'applications s'ouvre par défaut.

  • Messages contenant à la fois une notification et une charge utile de données, lorsqu'ils sont reçus en arrière-plan Dans ce cas, la notification est envoyée dans la barre d'état système de l'appareil, et la charge utile de données est envoyée dans les extras de l'intent de votre activité de lanceur.

En résumé :

État de l'application Notification Données Les deux
Premier plan onMessageReceived onMessageReceived onMessageReceived
Contexte Barre d'état système onMessageReceived Notification: barre d'état du système
Données: dans les extras de l'intent.
Pour en savoir plus sur les types de messages, consultez la section Notifications et messages de données.

Modifier le fichier manifeste de l'application

Pour utiliser FirebaseMessagingService, vous devez ajouter les éléments suivants dans le fichier manifeste de votre application:

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Nous vous recommandons également de définir des valeurs par défaut pour personnaliser l'apparence des notifications. Vous pouvez spécifier une icône et une couleur par défaut personnalisées qui sont appliquées chaque fois que des valeurs équivalentes ne sont pas définies dans la charge utile de la notification.

Ajoutez les lignes suivantes dans la balise application pour définir l'icône et la couleur par défaut personnalisées:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Android affiche l'icône par défaut personnalisée pour

  • Tous les messages de notification envoyés depuis l' éditeur de notifications.
  • Tout message de notification qui ne définit pas explicitement l'icône dans la charge utile de la notification.

Android utilise la couleur par défaut personnalisée pour

  • Tous les messages de notification envoyés depuis l' éditeur de notifications.
  • Tout message de notification qui ne définit pas explicitement la couleur dans la charge utile de la notification.

Si aucune icône par défaut personnalisée n'est définie et qu'aucune icône n'est définie dans la charge utile de la notification, Android affiche l'icône de l'application en blanc.

Ignorer onMessageReceived

En remplaçant la méthode FirebaseMessagingService.onMessageReceived, vous pouvez effectuer des actions en fonction de l'objet RemoteMessage reçu et obtenir les données du message:

Kotlin+KTX

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob()
        } else {
            // Handle message within 10 seconds
            handleNow()
        }
    }

    // Check if message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Ignorer onDeletedMessages

Dans certains cas, FCM peut ne pas envoyer de message. Cela se produit lorsqu'il y a trop de messages en attente (> 100) pour votre application sur un appareil particulier au moment de la connexion ou si l'appareil ne s'est pas connecté à FCM depuis plus d'un mois. Dans ce cas, vous pouvez recevoir un rappel vers FirebaseMessagingService.onDeletedMessages(). Lorsque l'instance de l'application reçoit ce rappel, elle doit effectuer une synchronisation complète avec votre serveur d'application. Si vous n'avez pas envoyé de message à l'application sur cet appareil au cours des quatre dernières semaines, FCM n'appellera pas onDeletedMessages().

Gérer les messages de notification dans une application en arrière-plan

Lorsque votre application est en arrière-plan, Android dirige les messages de notification vers la barre d'état système. Lorsque l'utilisateur appuie sur la notification, le lanceur d'applications s'ouvre par défaut.

Cela inclut les messages contenant à la fois une charge utile de notification et de données (et tous les messages envoyés depuis la console Notifications). Dans ce cas, la notification est envoyée dans la barre d'état système de l'appareil, et la charge utile de données est envoyée dans les extras de l'intent de votre activité de lanceur.

Pour en savoir plus sur la distribution des messages dans votre application, consultez le tableau de bord de reporting FCM, qui enregistre le nombre de messages envoyés et ouverts sur des appareils Apple et Android, ainsi que les données sur les "impressions" (notifications vues par les utilisateurs) pour les applications Android.

Créer des demandes d'envoi

Une fois que vous avez créé un sujet, soit en abonnant des instances d'application cliente au sujet côté client, soit via l'API du serveur, vous pouvez envoyer des messages au sujet. Si vous créez des requêtes d'envoi pour FCM pour la première fois, consultez le guide sur votre environnement serveur et FCM pour obtenir des informations importantes sur le contexte et la configuration.

Dans votre logique d'envoi sur le backend, spécifiez le nom de sujet souhaité comme indiqué:

Node.js

// The topic name can be optionally prefixed with "/topics/".
const topic = 'highScores';

const message = {
  data: {
    score: '850',
    time: '2:45'
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";

// See documentation on defining a message payload.
Message message = Message.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .setTopic(topic)
    .build();

// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

Python

# The topic name can be optionally prefixed with "/topics/".
topic = 'highScores'

# See documentation on defining a message payload.
message = messaging.Message(
    data={
        'score': '850',
        'time': '2:45',
    },
    topic=topic,
)

# Send a message to the devices subscribed to the provided topic.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// The topic name can be optionally prefixed with "/topics/".
topic := "highScores"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Topic: topic,
}

// Send a message to the devices subscribed to the provided topic.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// The topic name can be optionally prefixed with "/topics/".
var topic = "highScores";

// See documentation on defining a message payload.
var message = new Message()
{
    Data = new Dictionary<string, string>()
    {
        { "score", "850" },
        { "time", "2:45" },
    },
    Topic = topic,
};

// Send a message to the devices subscribed to the provided topic.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

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":{
    "topic" : "foo-bar",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message"
      }
   }
}

Commande cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "message": {
    "topic" : "foo-bar",
    "notification": {
      "body": "This is a Firebase Cloud Messaging Topic Message!",
      "title": "FCM Message"
    }
  }
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Pour envoyer un message à une combinaison de sujets, spécifiez une condition, qui est une expression booléenne qui spécifie les sujets cibles. Par exemple, la condition suivante envoie des messages aux appareils abonnés à TopicA et à TopicB ou TopicC:

"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"

FCM évalue d'abord les conditions entre parenthèses, puis l'expression de gauche à droite. Dans l'expression ci-dessus, un utilisateur abonné à un seul sujet ne reçoit pas le message. De même, un utilisateur qui ne s'abonne pas à TopicA ne reçoit pas le message. Ces combinaisons le reçoivent:

  • TopicA et TopicB
  • TopicA et TopicC

Vous pouvez inclure jusqu'à cinq thèmes dans votre expression conditionnelle.

Pour envoyer un message à une condition:

Node.js

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
const condition = '\'stock-GOOG\' in topics || \'industry-tech\' in topics';

// See documentation on defining a message payload.
const message = {
  notification: {
    title: '$FooCorp up 1.43% on the day',
    body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
  },
  condition: condition
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
String condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
Message message = Message.builder()
    .setNotification(Notification.builder()
        .setTitle("$GOOG up 1.43% on the day")
        .setBody("$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.")
        .build())
    .setCondition(condition)
    .build();

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

Python

# Define a condition which will send to devices which are subscribed
# to either the Google stock or the tech industry topics.
condition = "'stock-GOOG' in topics || 'industry-tech' in topics"

# See documentation on defining a message payload.
message = messaging.Message(
    notification=messaging.Notification(
        title='$GOOG up 1.43% on the day',
        body='$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',
    ),
    condition=condition,
)

# Send a message to devices subscribed to the combination of topics
# specified by the provided condition.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Condition: condition,
}

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
var condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
var message = new Message()
{
    Notification = new Notification()
    {
        Title = "$GOOG up 1.43% on the day",
        Body = "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
    },
    Condition = condition,
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

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":{
    "condition": "'dogs' in topics || 'cats' in topics",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message",
    }
  }
}

Commande cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "notification": {
    "title": "FCM Message",
    "body": "This is a Firebase Cloud Messaging Topic Message!",
  },
  "condition": "'dogs' in topics || 'cats' in topics"
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Étapes suivantes