Enviar mensajes a varios dispositivos

Para dirigir un mensaje a varios dispositivos, utilice la mensajería por tema . Esta función le permite enviar un mensaje a varios dispositivos que hayan optado por un tema en particular.

Este tutorial se centra en enviar mensajes temáticos desde su servidor de aplicaciones mediante el SDK de administración o la API REST para FCM, y en recibirlos y gestionarlos en una aplicación de Android. Cubriremos el manejo de mensajes tanto para aplicaciones en segundo plano como en primer plano. Se cubren todos los pasos para lograr esto, desde la configuración hasta la verificación.

Configurar el SDK

Esta sección puede cubrir los pasos que ya completó si configuró una aplicación cliente de Android para FCM o siguió los pasos para enviar su primer mensaje .

Antes de que empieces

  • Instale o actualice Android Studio a su última versión.

  • Asegúrese de que su proyecto cumpla con estos requisitos:

    • Se dirige al nivel API 19 (KitKat) o superior
    • Utiliza Android 4.4 o superior
    • Utiliza Jetpack (AndroidX) , que incluye cumplir con estos requisitos de versión:
      • com.android.tools.build:gradle v7.3.0 o posterior
      • compileSdkVersion 28 o posterior
  • Configure un dispositivo físico o use un emulador para ejecutar su aplicación.
    Tenga en cuenta que los SDK de Firebase que dependen de los servicios de Google Play requieren que el dispositivo o el emulador tenga instalados los servicios de Google Play.

  • Inicie sesión en Firebase con su cuenta de Google.

Si aún no tienes un proyecto de Android y solo quieres probar un producto de Firebase, puedes descargar uno de nuestros ejemplos de inicio rápido .

Crear un proyecto de Firebase

Antes de poder agregar Firebase a su aplicación de Android, debe crear un proyecto de Firebase para conectarse a su aplicación de Android. Visita Comprender los proyectos de Firebase para obtener más información sobre los proyectos de Firebase.

Registra tu aplicación con Firebase

Para usar Firebase en su aplicación de Android, debe registrar su aplicación con su proyecto de Firebase. Registrar su aplicación a menudo se denomina "agregar" su aplicación a su proyecto.

  1. Vaya a la consola de Firebase .

  2. En el centro de la página de descripción general del proyecto, haga clic en el ícono de Android ( ) o Agregar aplicación para iniciar el flujo de trabajo de configuración.

  3. Ingrese el nombre del paquete de su aplicación en el campo de nombre del paquete de Android .

  4. (Opcional) Ingrese otra información de la aplicación: apodo de la aplicación y certificado de firma de depuración SHA-1 .

  5. Haga clic en Registrar aplicación .

Agregar un archivo de configuración de Firebase

  1. Descargue y luego agregue el archivo de configuración de Firebase para Android ( google-services.json ) a su aplicación:

    1. Haga clic en Descargar google-services.json para obtener su archivo de configuración de Firebase Android.

    2. Mueva su archivo de configuración al directorio raíz del módulo (nivel de aplicación) de su aplicación.

  2. Para que los valores de su archivo de configuración google-services.json sean accesibles para los SDK de Firebase, necesita el complemento Gradle de servicios de Google ( google-services ).

    1. En su archivo Gradle de nivel raíz (nivel de proyecto) ( <project>/build.gradle.kts o <project>/build.gradle ), agregue el complemento de servicios de Google como una dependencia:

      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.1" 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.1' apply false
      }
      
    2. En el archivo Gradle de su módulo (nivel de aplicación) (normalmente <project>/<app-module>/build.gradle.kts o <project>/<app-module>/build.gradle ), agregue el complemento de servicios de 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'
        // ...
      }
      

Agregue SDK de Firebase a su aplicación

  1. En el archivo Gradle de su módulo (nivel de aplicación) (generalmente <project>/<app-module>/build.gradle.kts o <project>/<app-module>/build.gradle ), agregue la dependencia para Firebase Cloud Biblioteca de mensajería para Android. Recomendamos utilizar Firebase Android BoM para controlar el control de versiones de la biblioteca.

    Para una experiencia óptima con Firebase Cloud Messaging, recomendamos habilitar Google Analytics en su proyecto de Firebase y agregar el SDK de Firebase para Google Analytics a su aplicación.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:32.8.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")
    }
    

    Al usar Firebase Android BoM , su aplicación siempre usará versiones compatibles de las bibliotecas de Firebase Android.

    (Alternativa) Agregue dependencias de la biblioteca de Firebase sin usar la BoM

    Si elige no utilizar la BoM de Firebase, debe especificar cada versión de la biblioteca de Firebase en su línea de dependencia.

    Tenga en cuenta que si usa varias bibliotecas de Firebase en su aplicación, le recomendamos encarecidamente usar la BoM para administrar las versiones de la biblioteca, lo que garantiza que todas las versiones sean 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:23.4.1")
        implementation("com.google.firebase:firebase-analytics:21.6.1")
    }
    
    ¿Busca un módulo de biblioteca específico de Kotlin? A partir de octubre de 2023 (Firebase BoM 32.5.0) , tanto los desarrolladores de Kotlin como los de Java podrán depender del módulo de biblioteca principal (para más detalles, consulte las preguntas frecuentes sobre esta iniciativa ).

  2. Sincroniza tu proyecto de Android con archivos Gradle.

Suscribir la aplicación cliente a un tema

Las aplicaciones cliente pueden suscribirse a cualquier tema existente o pueden crear un tema nuevo. Cuando una aplicación cliente se suscribe a un nuevo nombre de tema (uno que aún no existe para su proyecto de Firebase), se crea un nuevo tema con ese nombre en FCM y cualquier cliente puede suscribirse a él posteriormente.

Para suscribirse a un tema, la aplicación cliente llama a Firebase Cloud Messaging subscribeToTopic() con el nombre del tema de FCM. Este método devuelve una Task , que puede ser utilizada por un oyente de finalización para determinar si la suscripción se realizó correctamente:

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

Para cancelar la suscripción, la aplicación cliente llama a Firebase Cloud Messaging unsubscribeFromTopic() con el nombre del tema.

Recibir y manejar mensajes temáticos.

FCM entrega mensajes temáticos de la misma manera que otros mensajes posteriores.

Para recibir mensajes, utilice un servicio que extienda FirebaseMessagingService . Su servicio debe anular las devoluciones de llamada onMessageReceived y onDeletedMessages .

La ventana de tiempo para manejar un mensaje puede ser inferior a 20 segundos dependiendo de los retrasos ocurridos antes de llamar onMessageReceived , incluidos retrasos del sistema operativo, el tiempo de inicio de la aplicación, el bloqueo del hilo principal por otras operaciones o llamadas anteriores onMessageReceived que tardan demasiado. Después de ese tiempo, varios comportamientos del sistema operativo, como la eliminación de procesos de Android o los límites de ejecución en segundo plano de Android O, pueden interferir con su capacidad para completar su trabajo.

onMessageReceived se proporciona para la mayoría de los tipos de mensajes, con las siguientes excepciones:

  • Mensajes de notificación entregados cuando su aplicación está en segundo plano . En este caso, la notificación se envía a la bandeja del sistema del dispositivo. Un usuario que toca una notificación abre el iniciador de aplicaciones de forma predeterminada.

  • Mensajes con carga útil de notificación y datos, cuando se reciben en segundo plano . En este caso, la notificación se envía a la bandeja del sistema del dispositivo y la carga útil de datos se entrega en los extras de la intención de la Actividad del iniciador.

En resumen:

Estado de la aplicación Notificación Datos Ambos
Primer plano onMessageReceived onMessageReceived onMessageReceived
Fondo Bandeja del sistema onMessageReceived Notificación: bandeja del sistema
Datos: en extras de la intención.
Para obtener más información sobre los tipos de mensajes, consulte Notificaciones y mensajes de datos .

Editar el manifiesto de la aplicación

Para usar FirebaseMessagingService , debes agregar lo siguiente en el manifiesto de tu aplicación:

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

Además, se recomienda establecer valores predeterminados para personalizar la apariencia de las notificaciones. Puede especificar un icono predeterminado personalizado y un color predeterminado personalizado que se aplican siempre que no se establezcan valores equivalentes en la carga útil de notificación.

Agregue estas líneas dentro de la etiqueta de la application para configurar el ícono predeterminado personalizado y el color personalizado:

<!-- 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 muestra el icono predeterminado personalizado para

  • Todos los mensajes de notificación enviados desde el redactor de notificaciones .
  • Cualquier mensaje de notificación que no establezca explícitamente el icono en la carga útil de notificación.

Android usa el color predeterminado personalizado para

  • Todos los mensajes de notificación enviados desde el redactor de notificaciones .
  • Cualquier mensaje de notificación que no establezca explícitamente el color en la carga útil de notificación.

Si no se establece ningún ícono predeterminado personalizado y no se establece ningún ícono en la carga útil de notificación, Android muestra el ícono de la aplicación en blanco.

Anular onMessageReceived

Al anular el método FirebaseMessagingService.onMessageReceived , puedes realizar acciones basadas en el objeto RemoteMessage recibido y obtener los datos del mensaje:

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

onDeletedMessages eliminados

En algunas situaciones, es posible que FCM no entregue un mensaje. Esto ocurre cuando hay demasiados mensajes (>100) pendientes para su aplicación en un dispositivo en particular en el momento en que se conecta o si el dispositivo no se ha conectado a FCM en más de un mes. En estos casos, puede recibir una devolución de llamada a FirebaseMessagingService.onDeletedMessages() . Cuando la instancia de la aplicación recibe esta devolución de llamada, debe realizar una sincronización completa con su servidor de aplicaciones. Si no ha enviado un mensaje a la aplicación en ese dispositivo en las últimas 4 semanas, FCM no llamará a onDeletedMessages() .

Manejar mensajes de notificación en una aplicación en segundo plano

Cuando su aplicación está en segundo plano, Android dirige los mensajes de notificación a la bandeja del sistema. Un toque del usuario en la notificación abre el iniciador de aplicaciones de forma predeterminada.

Esto incluye mensajes que contienen notificaciones y carga útil de datos (y todos los mensajes enviados desde la consola de notificaciones). En estos casos, la notificación se envía a la bandeja del sistema del dispositivo y la carga útil de datos se entrega en los extras de la intención de la Actividad del iniciador.

Para obtener información sobre la entrega de mensajes a su aplicación, consulte el panel de informes de FCM , que registra la cantidad de mensajes enviados y abiertos en dispositivos Apple y Android, junto con datos de "impresiones" (notificaciones vistas por los usuarios) para aplicaciones de Android.

Crear solicitudes de envío

Después de haber creado un tema, ya sea suscribiendo instancias de la aplicación cliente al tema en el lado del cliente o mediante la API del servidor , puede enviar mensajes al tema. Si es la primera vez que crea solicitudes de envío para FCM, consulte la guía de su entorno de servidor y FCM para obtener información importante sobre antecedentes y configuración.

En su lógica de envío en el backend, especifique el nombre del tema deseado como se muestra:

Nodo.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);

Pitón

# 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)

Ir

// 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);

DESCANSAR

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

comando de curvatura:

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

Para enviar un mensaje a una combinación de temas, especifique una condición , que es una expresión booleana que especifica los temas de destino. Por ejemplo, la siguiente condición enviará mensajes a dispositivos que estén suscritos a TopicA y a TopicB o TopicC :

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

FCM primero evalúa las condiciones entre paréntesis y luego evalúa la expresión de izquierda a derecha. En la expresión anterior, un usuario suscrito a un solo tema no recibe el mensaje. Asimismo, un usuario que no está suscrito a TopicA no recibe el mensaje. Estas combinaciones sí lo reciben:

  • TopicA y TopicB
  • TopicA y TopicC

Puede incluir hasta cinco temas en su expresión condicional.

Para enviar a una condición:

Nodo.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);

Pitón

# 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)

Ir

// 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);

DESCANSAR

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

comando de curvatura:

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

Próximos pasos