Envía mensajes a varios dispositivos

Firebase Cloud Messaging brinda dos maneras de enviar un mensaje a varios dispositivos:

Este instructivo se enfoca en el envío de mensajes por tema desde tu servidor de apps mediante los protocolos HTTP o XMPP para FCM, así como en la recepción y administración de ellos en una app de Android. Abordaremos la administración de mensajes en apps en segundo plano y en primer plano. Se incluyen todos los pasos para hacerlo, desde la configuración hasta la verificación.

Cómo configurar el SDK

Es posible que ya hayas completado algunos pasos de esta sección si configuraste una app cliente de Android para FCM o si ya enviaste tu primer mensaje.

Requisitos previos

  • Un dispositivo que ejecute los siguientes componentes:
    • Android 4.1 (nivel de API 16, Jelly Bean) o posterior
    • Servicios de Google Play 15.0.0 o posterior
  • La versión más reciente de Android Studio

Si aún no tienes un proyecto de Android Studio y simplemente quieres probar una función de Firebase, puedes descargar una de las muestras de inicio rápido. Si estás usando un inicio rápido, recuerda obtener el ID de la aplicación desde el archivo build.gradle que se encuentra en la carpeta del módulo de tu proyecto (por lo general, app/), ya que necesitarás el nombre de este paquete para el siguiente paso.

Agrega Firebase a tu app

Es hora de agregar Firebase a la app. Primero, necesitarás un proyecto y un archivo de configuración de Firebase para la app.

Para crear un proyecto de Firebase:

  1. Dirígete a Firebase console.

  2. Haz clic en Agregar proyecto, luego selecciona o ingresa un Nombre del proyecto.

    • Si hay un proyecto de Google existente asociado con tu app, selecciónalo desde el menú desplegable Nombre del proyecto.
    • Si no hay un proyecto de Google existente, ingresa un nuevo Nombre del proyecto.
  3. Opcional: Edita el ID del proyecto.

    Firebase asignará de manera automática un ID único a tu proyecto de Firebase. Este identificador se muestra en los servicios de Firebase visibles de forma pública, por ejemplo:

    • URL predeterminada de Realtime Database: your-project-id.firebaseio.com
    • Nombre predeterminado del depósito de Cloud Storage: your-project-id.appspot.com
    • Subdominio predeterminado de Hosting: your-project-id.firebaseapp.com
  4. Sigue los pasos de configuración restantes y, luego, haz clic en Crear proyecto (o Agregar Firebase si usas un proyecto de Google existente).

Firebase aprovisiona los recursos para tu proyecto de forma automática. Este proceso suele tardar algunos minutos. Cuando finalice, verás la página de descripción general del proyecto en Firebase console.

Ahora que tienes un proyecto, puedes agregar tu app para Android:

  1. Haz clic en Agrega Firebase a tu app para Android y sigue los pasos de la configuración. Si importas un proyecto de Google existente, es posible que esto ocurra de forma automática y solo tengas que descargar el archivo de configuración.

  2. Ingresa el nombre del paquete de la app cuando se te solicite. Es importante que ingreses el ID del paquete que usa la app. Esta configuración solo puede hacerse cuando agregas la app al proyecto de Firebase.

  3. Agrega el archivo de configuración de Firebase para Android a la app, como se indica a continuación:

    1. Haz clic en Descargar google-services.json a fin de obtener el archivo de configuración de Firebase para Android (google-services.json).

      Puedes volver a descargar el archivo de configuración de Firebase para Android cuando quieras.

    2. Traslada el archivo de configuración al mismo directorio en donde se ubica el archivo build.gradle del nivel de raíz.

  4. Después de agregar el código de inicialización, ejecuta tu app para verificar con la consola que instalaste Firebase correctamente.

Agrega el SDK

Si quieres integrar las bibliotecas de Firebase a uno de tus proyectos, debes completar algunos pasos básicos para preparar tu proyecto de Android Studio. Es posible que ya lo hayas hecho en el proceso de agregar Firebase a tu app.

Primero, agrega reglas a tu archivo build.gradle de nivel de raíz para incluir el complemento de google-services y el repositorio Maven de Google:

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:4.2.0' // google-services plugin
    }
}

allprojects {
    // ...
    repositories {
        google() // Google's Maven repository
        // ...
    }
}

Luego, en el archivo Gradle de tu módulo (generalmente, app/build.gradle), agrega la línea apply plugin en la parte inferior del archivo para habilitar el complemento de Gradle:

apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  implementation 'com.google.firebase:firebase-core:16.0.7'
  implementation 'com.google.firebase:firebase-messaging:17.3.4'
  // Getting a "Could not find" error? Make sure you have
  // added the Google maven respository to your root build.gradle
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

También debes agregar las dependencias para los SDK de Firebase que deseas usar. Te recomendamos comenzar con com.google.firebase:firebase-core, que proporciona la función de Google Analytics para Firebase. Consulta la lista de bibliotecas disponibles.

Suscribe la app cliente a un tema

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

Para suscribirse a un tema, la app cliente llama a subscribeToTopic() de Firebase Cloud Messaging con el nombre del tema de FCM. Este método muestra una Task, que se puede usar en un agente de escucha de finalización para determinar si la suscripción se realizó correctamente:

Java
Android

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

Kotlin
Android

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener { task ->
            var msg = getString(R.string.msg_subscribed)
            if (!task.isSuccessful) {
                msg = getString(R.string.msg_subscribe_failed)
            }
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        }

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

Recibe y administra mensajes a temas

FCM entrega mensajes a temas de la misma manera que otros mensajes descendentes.

Para recibir mensajes, usa un servicio que extienda FirebaseMessagingService. El servicio debe anular las devoluciones de llamada onMessageReceived y onDeletedMessages. Debe administrar cualquier mensaje en un plazo de 20 segundos desde su recepción (10 segundos en Android Marshmallow). El margen de tiempo puede ser más breve según los retrasos del SO incurridos antes de llamar a onMessageReceived. Después de ese tiempo, varios comportamientos del SO, como los límites de ejecución en segundo plano de Android O, pueden interferir en tu capacidad para finalizar el trabajo. Si deseas obtener más información, consulta la descripción general en la prioridad del mensaje.

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

  • Mensajes de notificación enviados cuando la app está en segundo plano. En este caso, la notificación se entrega a la bandeja del sistema del dispositivo. Cuando un usuario presiona una notificación, abre el selector de aplicaciones de forma predeterminada.

  • Mensajes con carga útil de notificaciones y datos cuando se reciben en segundo plano. En este caso, la notificación se entrega a la bandeja del sistema del dispositivo y la carga útil de datos se entrega en los adicionales del intent de tu actividad iniciadora.

Resumen:

Estado de la app Notificación Datos Ambos
Primer plano onMessageReceived onMessageReceived onMessageReceived
Segundo plano Bandeja del sistema onMessageReceived Notificación: Bandeja del sistema
Datos: En extras del intent
Para obtener más información acerca de los tipos de mensajes, consulta Mensajes de notificación y de datos.

Edita el manifiesto de la app

Para usar FirebaseMessagingService, debes agregar lo siguiente al manifiesto de tu app:

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

Además, te recomendamos establecer valores predeterminados para personalizar el aspecto de las notificaciones. Puedes especificar un ícono y un color predeterminados y personalizados que se aplican cada vez que no se establecen valores equivalentes en la carga útil de notificación.

Agrega estas líneas en la etiqueta application para establecer el ícono predeterminado 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 ícono predeterminado personalizado para lo siguiente:

  • Todos los mensajes de notificación enviados desde el Compositor de Notifications.
  • Todos los mensajes de notificación que no establecen el ícono de manera explícita en la carga útil de la notificación.

Android usa el color predeterminado personalizado para lo siguiente:

  • Todos los mensajes de notificación enviados desde el Compositor de Notifications.
  • Todos los mensajes de notificación que no definen el color de manera explícita en la carga útil de la notificación.

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

Anula onMessageReceived

Puedes anular el método FirebaseMessagingService.onMessageReceived para realizar acciones según el objeto RemoteMessage recibido y obtener los datos del mensaje:

Java
Android

@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 Firebase Job Dispatcher.
            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.
}

Kotlin
Android

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.
    remoteMessage?.data?.isNotEmpty()?.let {
        Log.d(TAG, "Message data payload: " + remoteMessage.data)

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
            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.
}

Anula onDeletedMessages

En algunas situaciones, es posible que FCM no envíe un mensaje. Esto ocurre cuando hay muchos mensajes (más de 100) pendientes para tu app en un dispositivo específico al momento de conectarse o si el dispositivo no se conecta a FCM en más de un mes. En estos casos, es posible que recibas una devolución de llamada a FirebaseMessagingService.onDeletedMessages(). Cuando la instancia de app recibe esta devolución de llamada, debería ejecutar una sincronización completa con tu servidor de apps. Si no enviaste un mensaje a la app en ese dispositivo en las últimas 4 semanas, FCM no llamará a onDeletedMessages().

Maneja mensajes de notificación en una app en segundo plano

Cuando tu app está en segundo plano, Android dirige los mensajes de notificación a la bandeja del sistema. Cuando un usuario presiona una notificación, se abre el selector de aplicaciones de forma predeterminada.

Esto incluye los mensajes que contienen carga útil de notificaciones y datos (y todos los mensajes que se envíen desde la consola de Notifications). En estos casos, la notificación se entrega a la bandeja del sistema del dispositivo, y la carga de datos útil se entrega en los adicionales del intent de tu actividad iniciadora.

Para obtener estadísticas de la entrega de mensajes a tu app, consulta el panel de mensajes de FCM que registra la cantidad de mensajes enviados y abiertos en dispositivos iOS y Android, junto con datos de “impresiones” (notificaciones vistas por los usuarios) para apps de Android.

Aplicaciones con restricción en segundo plano (Android P o versiones posteriores)

A partir de enero de 2019, FCM no entregará mensajes a las aplicaciones que el usuario configuró con restricción en segundo plano (por ejemplo, mediante Configuración -> Apps y notificaciones -> [Nombre de la app] -> Batería). Cuando se quite la restricción en segundo plano de tu app, esta podrá recibir mensajes nuevos como antes. Para evitar que se pierdan los mensajes y otras consecuencias de la restricción en segundo plano, asegúrate de evitar los comportamientos incorrectos que se indican en la iniciativa Android vitals. Estos comportamientos podrían causar que el dispositivo Android recomiende al usuario que configure la restricción en segundo plano para tu app. Puedes comprobar si tu app tiene habilitada la restricción en segundo plano mediante el método isBackgroundRestricted().

Crea solicitudes de envío

Enviar mensajes a un tema de Firebase Cloud Messaging es muy similar a enviar mensajes a un dispositivo individual o a un grupo de usuarios. El servidor de apps establece la clave to con el valor /topics/yourTopic. Los desarrolladores pueden elegir cualquier nombre de tema que coincida con la expresión regular "/topics/[a-zA-Z0-9-_.~%]+".

Para enviar mensajes a combinaciones de varios temas, el servidor de apps debe configurar la clave condition (en lugar de la clave to) como una condición booleana que especifique los temas de destino. Por ejemplo, para enviar mensajes a dispositivos suscritos a TopicA y a TopicB o TopicC:

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

En primer lugar, FCM evalúa las condiciones en paréntesis y, luego, evalúa la expresión de izquierda a derecha. En la expresión que se observa en este ejemplo, los usuarios suscritos a uno solo de los temas no recibirán el mensaje. Asimismo, los usuarios que no estén suscritos a TopicA tampoco lo recibirán. Las siguientes combinaciones sí lo reciben:

  • TopicA y TopicB
  • TopicA y TopicC

Puedes incluir hasta cinco temas en tu expresión condicional y se admiten paréntesis. Operadores compatibles: &&, ||, !. Ten en cuenta el uso de !:

!('TopicA' in topics)

Con esta expresión, todas las instancias que no se suscriben a TopicA, incluidas las instancias de app que no se suscriben a ningún tema, reciben el mensaje.

Para obtener más detalles sobre las claves de servidor de apps, consulta la información de referencia sobre el protocolo del servidor de conexiones HTTP o XMPP que seleccionaste. Los ejemplos de esta página muestran cómo enviar mensajes a temas mediante los protocolos respectivos.

Solicitud HTTP POST del tema

Envía a un tema individual:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

Envía a dispositivos suscritos a los temas "dogs" o "cats":

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

Respuesta HTTP del tema

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

Mensaje XMPP del tema

Envía a un tema individual:

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

Envía a dispositivos suscritos a los temas "dogs" o "cats":

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

Respuesta XMPP del tema

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

Cuando realizas una solicitud de envío por temas, pueden pasar hasta 30 segundos antes de que el servidor de FCM muestre una respuesta de ejecución correcta o con errores. Asegúrate de configurar el valor de tiempo de espera del servidor de apps en la solicitud de manera acorde.

Para ver la lista completa de opciones de mensaje, consulta la información de referencia del protocolo de servidor de conexiones que seleccionaste, HTTP o XMPP.

Pasos siguientes

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.