Compartir a través de


Remote Notifications with Firebase Cloud Messaging (Notificaciones remotas con Firebase Cloud Messaging)

En este tutorial se proporciona una explicación paso a paso de cómo usar Firebase Cloud Messaging para implementar notificaciones remotas (también llamadas notificaciones push) en una aplicación de Xamarin.Android. Muestra cómo implementar las distintas clases necesarias para las comunicaciones con Firebase Cloud Messaging (FCM), proporciona ejemplos de cómo configurar el manifiesto de Android para acceder a FCM y muestra la mensajería de bajada mediante la consola de Firebase.

Introducción a las notificaciones de FCM

En este tutorial, se creará una aplicación básica denominada FCMClient para ilustrar los aspectos básicos de la mensajería FCM. FCMClient comprueba la presencia de Google Play Services, recibe tokens de registro de FCM, muestra notificaciones remotas que envía desde la consola de Firebase y se suscribe a mensajes de tema:

Captura de pantalla de ejemplo de la aplicación

Se explorarán las siguientes áreas temáticas:

  1. Notificaciones en segundo plano

  2. Mensajes de tema

  3. Notificaciones en primer plano

Durante este tutorial, agregará funcionalidad de forma incremental a FCMClient y la ejecutará en un dispositivo o emulador para comprender cómo interactúa con FCM. Usará el registro para presenciar transacciones de aplicaciones en directo con servidores FCM y observará cómo se generan las notificaciones a partir de mensajes FCM que escriba en la GUI de notificaciones de la consola de Firebase.

Requisitos

Le será útil familiarizarse con los diferentes tipos de mensajes que Firebase Cloud Messaging puede enviar. La carga del mensaje determinará cómo recibirá una aplicación cliente y procesará el mensaje.

Para poder continuar con este tutorial, debe adquirir las credenciales necesarias para usar los servidores FCM de Google; este proceso se explica en Firebase Cloud Messaging. En concreto, debe descargar el archivo google-services.json para usarlo con el código de ejemplo presentado en este tutorial. Si aún no ha creado un proyecto en la consola de Firebase (o si aún no ha descargado el archivo google-services.json), consulte Firebase Cloud Messaging.

Para ejecutar la aplicación de ejemplo, necesitará un dispositivo de prueba o emulador Android que sea compatible con Firebase. Firebase Cloud Messaging admite clientes que se ejecutan en Android 4.0 o posterior, y estos dispositivos también deben tener instalada la aplicación Google Play Store (se requiere Google Play Services 9.2.1 o posterior). Si aún no tiene instalada la aplicación Google Play Store en su dispositivo, visite el sitio web de Google Play para descargarla e instalarla. También puede usar el emulador de Android SDK con Google Play Services instalado en lugar de un dispositivo de prueba (no tiene que instalar Google Play Store si usa el emulador de Android SDK).

Iniciar un proyecto de aplicación

Para empezar, cree un nuevo proyecto de Xamarin.Android vacío denominado FCMClient. Si no conoce la creación de proyectos de Xamarin.Android, consulte Hello, Android. Una vez creada la nueva aplicación, el siguiente paso consiste en establecer el nombre del paquete e instalar varios paquetes NuGet que se usarán para la comunicación con FCM.

Establecer el nombre del paquete

En Firebase Cloud Messaging, especificó un nombre de paquete para la aplicación habilitada para FCM. Este nombre de paquete también actúa como el identificador de aplicación asociado a la clave de API. Configure la aplicación para que use este nombre de paquete:

  1. Abra las propiedades del proyecto de FCMClient.

  2. En la página Manifiesto de Android, establezca el nombre del paquete.

En el ejemplo siguiente, el nombre del paquete se establece en com.xamarin.fcmexample:

Establecer el nombre del paquete

Mientras actualiza el manifiesto de Android, compruebe también que el permiso Internet esté habilitado.

Importante

La aplicación cliente no podrá recibir un token de registro de FCM si este nombre de paquete no coincide exactamente con el nombre del paquete que se escribió en la consola de Firebase.

Agregar el paquete base de Google Play Services de Xamarin

Dado que Firebase Cloud Messaging depende de Google Play Services, el paquete NuGet base de Xamarin Google Play Services debe agregarse al proyecto de Xamarin.Android. Necesitará la versión 29.0.0.2 o posterior.

  1. En Visual Studio, haga clic con el botón derecho en Referencias > Administrar paquetes NuGet....

  2. Haga clic en la pestaña Examinar y busque Xamarin.GooglePlayServices.Base.

  3. Instale este paquete en el proyecto FCMClient:

    Instalar Google Play Services Base

Si recibe un error durante la instalación de NuGet, cierre el proyecto FCMClient, ábralo de nuevo y vuelva a intentar la instalación de NuGet.

Al instalar Xamarin.GooglePlayServices.Base, también se instalan todas las dependencias necesarias. Edite MainActivity.cs y agregue la siguiente instrucción using:

using Android.Gms.Common;

Esta instrucción hace que la clase GoogleApiAvailability de Xamarin.GooglePlayServices.Base esté disponible para el código FCMClient. GoogleApiAvailability se usa para comprobar la presencia de Google Play Services.

Agregar el paquete de mensajería de Xamarin Firebase

Para recibir mensajes de FCM, el paquete NuGet Xamarin Firebase: mensajería debe agregarse al proyecto de aplicación. Sin este paquete, una aplicación Android no puede recibir mensajes de servidores FCM.

  1. En Visual Studio, haga clic con el botón derecho en Referencias > Administrar paquetes NuGet....

  2. Busque Xamarin.Firebase.Messaging.

  3. Instale este paquete en el proyecto FCMClient:

    Instalar Xamarin Firebase Messaging

Al instalar Xamarin.Firebase.Messaging, también se instalan todas las dependencias necesarias.

Luego, edite MainActivity.cs y agregue las siguientes instrucciones using:

using Firebase.Messaging;
using Firebase.Iid;
using Android.Util;

Las dos primeras instrucciones hacen que los tipos del paquete NuGet Xamarin.Firebase.Messaging estén disponibles para el código FCMClient. Android.Util agrega funcionalidad de registro que se usará para observar transacciones con FMS.

Adición del archivo JSON de Google Services

El siguiente paso es agregar el archivo google-services.json al directorio raíz del proyecto:

  1. Copie google-services.json en la carpeta del proyecto.

  2. Agregue google-services.json al proyecto de aplicación (haga clic en Mostrar todos los archivos en el Explorador de soluciones, haga clic con el botón derecho en google-services.json y, a continuación, seleccione Incluir en el proyecto).

  3. Seleccione google services.json en la ventana del Explorador de soluciones.

  4. En el panel Propiedades, establezca la acción de compilación en GoogleServicesJson:

    Establecer la acción de compilación en GoogleServicesJson

    Nota:

    Si no se muestra la acción de compilación GoogleServicesJson, guarde y cierre la solución y vuelva a abrirla.

Cuando se agrega google-services.json al proyecto (y se establece la acción de compilación de GoogleServicesJson), el proceso de compilación extrae el identificador de cliente y la clave de API y, a continuación, agrega estas credenciales al AndroidManifest.xml combinado/generado que reside en obj/Debug/android/AndroidManifest.xml. Este proceso de combinación agrega automáticamente los permisos y otros elementos FCM necesarios para la conexión a los servidores FCM.

Buscar Google Play Services y crear un canal de notificación

Google recomienda que las aplicaciones Android comprueben la presencia del APK de Google Play Services antes de acceder a las características de Google Play Services (para obtener más información, consulte Buscar servicios de Google Play).

Primero se creará un diseño inicial para la interfaz de usuario de la aplicación. Edite Resources/layout/Main.axml y reemplace su contenido por el siguiente XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp">
    <TextView
        android:text=" "
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/msgText"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:padding="10dp" />
</LinearLayout>

TextView se usará para mostrar mensajes que indiquen si Google Play Services está instalado. Guarde los cambios en Main.axml.

Edite MainActivity.cs y agregue las siguientes variables de instancia a la clase MainActivity:

public class MainActivity : AppCompatActivity
{
    static readonly string TAG = "MainActivity";

    internal static readonly string CHANNEL_ID = "my_notification_channel";
    internal static readonly int NOTIFICATION_ID = 100;

    TextView msgText;

Las variables CHANNEL_ID y NOTIFICATION_ID se usarán en el método CreateNotificationChannel que se agregará a MainActivity más adelante en este tutorial.

En el ejemplo siguiente, el método OnCreate comprobará que Google Play Services está disponible antes de que la aplicación intente usar los servicios FCM. Agregue el siguiente método a la clase MainActivity:

public bool IsPlayServicesAvailable ()
{
    int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable (this);
    if (resultCode != ConnectionResult.Success)
    {
        if (GoogleApiAvailability.Instance.IsUserResolvableError (resultCode))
            msgText.Text = GoogleApiAvailability.Instance.GetErrorString (resultCode);
        else
        {
            msgText.Text = "This device is not supported";
            Finish ();
        }
        return false;
    }
    else
    {
        msgText.Text = "Google Play Services is available.";
        return true;
    }
}

Este código comprueba el dispositivo para ver si está instalado el APK de Google Play Services. Si no está instalado, se muestra un mensaje en TextBox que indica al usuario que descargue un APK desde Google Play Store (o para habilitarlo en la configuración del sistema del dispositivo).

Las aplicaciones que se ejecutan en Android 8.0 (nivel de API 26) o superior deben crear un canal de notificación para publicar sus notificaciones. Agregue el siguiente método a la clase MainActivity que creará el canal de notificación (si es necesario):

void CreateNotificationChannel()
{
    if (Build.VERSION.SdkInt < BuildVersionCodes.O)
    {
        // Notification channels are new in API 26 (and not a part of the
        // support library). There is no need to create a notification
        // channel on older versions of Android.
        return;
    }

    var channel = new NotificationChannel(CHANNEL_ID,
                                          "FCM Notifications",
                                          NotificationImportance.Default)
                  {

                      Description = "Firebase Cloud Messages appear in this channel"
                  };

    var notificationManager = (NotificationManager)GetSystemService(Android.Content.Context.NotificationService);
    notificationManager.CreateNotificationChannel(channel);
}

Reemplace el método OnCreate con el código siguiente:

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    SetContentView (Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    IsPlayServicesAvailable ();

    CreateNotificationChannel();
}

IsPlayServicesAvailable se llama al final de OnCreate para que la comprobación de Google Play Services se ejecute cada vez que se inicie la aplicación. Se llama al método CreateNotificationChannel para asegurarse de que existe un canal de notificación para dispositivos que ejecutan Android 8 o posterior. Si la aplicación tiene un método OnResume, también debe llamar a IsPlayServicesAvailable desde OnResume. Vuelva a generar completamente y ejecute la aplicación. Si todo está configurado correctamente, debería ver una pantalla similar a la siguiente captura de pantalla:

La aplicación indica que Google Play Services está disponible

Si no obtiene este resultado, compruebe que el APK de Google Play Services está instalado en su dispositivo (para obtener más información, consulte Configurar Google Play Services). Compruebe también que ha agregado el paquete Xamarin.Google.Play.Services.Base al proyecto FCMClient como se explicó anteriormente.

Agregar el receptor de identificadores de instancia

El siguiente paso es agregar un servicio que extiende FirebaseInstanceIdService para controlar la creación, rotación y actualización de tokens de registro de Firebase. El servicio FirebaseInstanceIdService es necesario para que FCM pueda enviar mensajes al dispositivo. Cuando el servicio FirebaseInstanceIdService se agrega a la aplicación cliente, la aplicación recibirá automáticamente mensajes FCM y los mostrará como notificaciones cada vez que la aplicación esté en segundo plano.

Declarar el receptor en el manifiesto de Android

Edite AndroidManifest.xml e inserte los siguientes elementos <receiver> en la sección <application>:

<receiver
    android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
    android:exported="false" />
<receiver
    android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="${applicationId}" />
    </intent-filter>
</receiver>

El XML hace lo siguiente:

  • Declara una implementación FirebaseInstanceIdReceiver que proporciona un identificador único para cada instancia de aplicación. Este receptor también autentica y autoriza acciones.

  • Declara una implementación interna FirebaseInstanceIdInternalReceiver que se usa para iniciar los servicios de forma segura.

  • El id. de la aplicación se almacena en el archivo google-services.json que se agregó al proyecto. Los enlaces de Firebase de Xamarin.Android reemplazarán el token ${applicationId} por el id. de la aplicación; la aplicación cliente no requiere ningún código adicional para proporcionar el id. de la aplicación.

FirebaseInstanceIdReceiver es un objeto WakefulBroadcastReceiver que recibe eventos FirebaseInstanceId y FirebaseMessaging, y los entrega a la clase que usted deriva de FirebaseInstanceIdService.

Implementación del servicio de id. de instancia de Firebase

El trabajo de registrar la aplicación con FCM se controla mediante el servicio personalizado FirebaseInstanceIdService que proporcione. FirebaseInstanceIdService realiza las tareas siguientes:

  1. Usa la API de id. de instancia para generar tokens de seguridad que autorizan a la aplicación cliente a acceder a FCM y al servidor de aplicaciones. A cambio, la aplicación devuelve un token de registro de FCM.

  2. Reenvía el token de registro al servidor de aplicaciones si el servidor de aplicaciones lo requiere.

Agregue un nuevo archivo denominado MyFirebaseIIDService.cs y reemplace su código de plantilla por lo siguiente:

using System;
using Android.App;
using Firebase.Iid;
using Android.Util;

namespace FCMClient
{
    [Service]
    [IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
    public class MyFirebaseIIDService : FirebaseInstanceIdService
    {
        const string TAG = "MyFirebaseIIDService";
        public override void OnTokenRefresh()
        {
            var refreshedToken = FirebaseInstanceId.Instance.Token;
            Log.Debug(TAG, "Refreshed token: " + refreshedToken);
            SendRegistrationToServer(refreshedToken);
        }
        void SendRegistrationToServer(string token)
        {
            // Add custom implementation, as needed.
        }
    }
}

Este servicio implementa un método OnTokenRefresh que se invoca cuando se crea o cambia inicialmente el token de registro. Cuando se ejecuta OnTokenRefresh, recupera el token más reciente de la propiedad FirebaseInstanceId.Instance.Token (que FCM actualiza de forma asincrónica). En este ejemplo, se registra el token actualizado para que se pueda ver en la ventana de salida:

var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);

OnTokenRefresh se invoca con poca frecuencia: se usa para actualizar el token en las siguientes circunstancias:

  • Cuando la aplicación está instalada o desinstalada.

  • Cuando el usuario elimina los datos de la aplicación.

  • Cuando la aplicación borra el identificador de instancia.

  • Cuando se ha puesto en peligro la seguridad del token.

Según la documentación del identificador de instancia de Google, el servicio de id. de instancia de FCM solicitará que la aplicación actualice su token periódicamente (normalmente, cada 6 meses).

OnTokenRefresh también llama a SendRegistrationToAppServer para asociar el token de registro del usuario a la cuenta del lado servidor (si existe) que mantiene la aplicación:

void SendRegistrationToAppServer (string token)
{
    // Add custom implementation here as needed.
}

Dado que esta implementación depende del diseño del servidor de aplicaciones, se proporciona un cuerpo de método vacío en este ejemplo. Si el servidor de aplicaciones requiere información de registro de FCM, modifique SendRegistrationToAppServer para asociar el token de identificador de instancia de FCM del usuario con cualquier cuenta del lado servidor mantenida por la aplicación. (Tenga en cuenta que el token es opaco para la aplicación cliente).

Cuando se envía un token al servidor de aplicaciones, SendRegistrationToAppServer debe mantener un valor booleano para indicar si el token se ha enviado al servidor. Si este valor booleano es false, SendRegistrationToAppServer envía el token al servidor de aplicaciones; de lo contrario, el token ya se envió al servidor de aplicaciones en una llamada anterior. En algunos casos (como este ejemplo de FCMClient), el servidor de aplicaciones no necesita el token; por lo tanto, este método no es necesario para este ejemplo.

Implementación del código de aplicación cliente

Ahora que los servicios receptores están en vigor, el código de la aplicación cliente se puede escribir para aprovechar estos servicios. En las secciones siguientes, se agrega un botón a la interfaz de usuario para registrar el token de registro (también denominado token de identificador de instancia) y se agrega más código a MainActivity para ver información de Intent cuando la aplicación se inicia desde una notificación:

Botón Registrar token agregado a la pantalla de la aplicación

Registrar tokens

El código agregado en este paso solo está pensado para fines de demostración: una aplicación cliente de producción no tendría necesidad de registrar tokens de registro. Edite Resources/layout/Main.axml y agregue la siguiente declaración Button inmediatamente después del elemento TextView:

<Button
  android:id="@+id/logTokenButton"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:text="Log Token" />

Agregue el siguiente código al final del método MainActivity.OnCreate:

var logTokenButton = FindViewById<Button>(Resource.Id.logTokenButton);
logTokenButton.Click += delegate {
    Log.Debug(TAG, "InstanceID token: " + FirebaseInstanceId.Instance.Token);
};

Este código registra el token actual en la ventana de salida cuando se pulsa el botón Registrar token.

Control de intenciones de notificación

Cuando el usuario pulsa una notificación emitida desde FCMClient, los datos que acompañan a ese mensaje de notificación están disponibles en extras de Intent. Edite MainActivity.cs y agregue el código siguiente en la parte superior del método OnCreate (antes de la llamada a IsPlayServicesAvailable):

if (Intent.Extras != null)
{
    foreach (var key in Intent.Extras.KeySet())
    {
        var value = Intent.Extras.GetString(key);
        Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
    }
}

El iniciador de la aplicación Intent se desencadena cuando el usuario pulsa su mensaje de notificación, por lo que este código registrará los datos adjuntos en la ventana de salida Intent. Si se debe activar otro Intent, el campo del mensaje de notificación click_action debe establecerse en ese Intent (el iniciador Intent se usa cuando no se especifica click_action).

Notificaciones en segundo plano

Compile y ejecute la aplicación FCMClient. Se muestra el botón Registrar token:

Se muestra el botón Registrar token

Pulse el botón Registrar token. Se debe mostrar un mensaje similar al siguiente en la ventana de salida del IDE:

Token de id. de instancia que se muestra en la ventana Salida

La cadena larga etiquetada con token es el token de identificador de instancia que pegará en la consola de Firebase: seleccione y copie esta cadena en el Portapapeles. Si no ve un token de identificador de instancia, agregue la siguiente línea a la parte superior del método OnCreate para comprobar que google-services.json se ha analizado correctamente:

Log.Debug(TAG, "google app id: " + GetString(Resource.String.google_app_id));

El valor google_app_id registrado en la ventana de salida debe coincidir con el valor mobilesdk_app_id registrado en google-services.json. Msbuild genera el objeto Resource.String.google_app_id al procesar google-services.json.

Envío de un mensaje

Inicie sesión en la consola de Firebase, seleccione el proyecto, haga clic en Notificaciones y haga clic en ENVIAR SU PRIMER MENSAJE:

Botón Enviar su primer mensaje

En la página Redactar mensaje, escriba el texto del mensaje y seleccione Dispositivo único. Copie el token de identificador de instancia de la ventana de salida del IDE y péguelo en el campo token de registro de FCM de la consola de Firebase:

Cuadro de diálogo Redactar mensaje

En el dispositivo (o emulador) de Android, deje en segundo plano la aplicación al pulsar el botón Información general de Android y tocar la pantalla principal. Cuando el dispositivo esté listo, haga clic en ENVIAR MENSAJE en la consola de Firebase:

Botón Enviar mensaje

Cuando se muestre el cuadro de diálogo Revisar mensaje, haga clic en ENVIAR. El icono de notificación debe aparecer en el área de notificación del dispositivo (o emulador):

Se muestra el icono de notificación

Abra el icono de notificación para ver el mensaje. El mensaje de notificación debe ser exactamente lo que se ha escrito en el campo Texto del mensaje de la consola de Firebase:

El mensaje de notificación se muestra en el dispositivo

Pulse el icono de notificación para iniciar la aplicación FCMClient. Los extras de Intent enviados a FCMClient se muestran en la ventana de salida del IDE:

Listas adicionales de intención a partir de clave, id. de mensaje y clave contraída

En este ejemplo, la clave from se establece en el número de proyecto Firebase de la aplicación (en este ejemplo, 41590732) y collapse_key se establece en su nombre de paquete (com.xamarin.fcmexample). Si no recibe un mensaje, intente eliminar la aplicación FCMClient en el dispositivo (o emulador) y repita los pasos anteriores.

Nota:

Si cierra la aplicación a la fuerza, FCM dejará de entregar notificaciones. Android impide que las difusiones del servicio en segundo plano inicien accidentalmente o de forma innecesaria componentes de aplicaciones detenidas. (Para obtener más información sobre este comportamiento, consulte Controles de inicio en aplicaciones detenidas). Por este motivo, es necesario desinstalar manualmente la aplicación cada vez que la ejecute y detenerla desde una sesión de depuración, lo que obliga a FCM a generar un nuevo token para que se sigan recibiendo los mensajes.

Agregar un icono de notificación predeterminado personalizado

En el ejemplo anterior, el icono de notificación se establece en el icono de la aplicación. El siguiente XML configura un icono predeterminado personalizado para las notificaciones. Android muestra este icono predeterminado personalizado para todos los mensajes de notificación en los que el icono de notificación no está establecido explícitamente.

Para agregar un icono de notificación predeterminado personalizado, agregue el icono al directorio Resources/drawable, edite AndroidManifest.xml e inserte el siguiente elemento <meta-data> en la sección <application>:

<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />

En este ejemplo, el icono de notificación que reside en Resources/drawable/ic_stat_ic_notification.png se usará como icono de notificación predeterminado personalizado. Si un icono predeterminado personalizado no está configurado en AndroidManifest.xml y no se establece ningún icono en la carga de notificación, Android usa el icono de aplicación como icono de notificación (como se muestra en la captura de pantalla del icono de notificación anterior).

Control de mensajes de tema

El código escrito hasta ahora controla los tokens de registro y agrega funcionalidad de notificación remota a la aplicación. En el ejemplo siguiente se agrega código que escucha mensajes de tema y los reenvía al usuario como notificaciones remotas. Los mensajes de tema son mensajes FCM que se envían a uno o varios dispositivos que se suscriben a un tema determinado. Para obtener más información sobre los mensajes de tema, consulte Mensajería de temas.

Suscripción a un tema

Edite Resources/layout/Main.axml y agregue la siguiente declaración Button inmediatamente después del elemento Button:

<Button
  android:id="@+id/subscribeButton"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:layout_marginTop="20dp"
  android:text="Subscribe to Notifications" />

Este XML agrega un botón Suscribirse a la notificación al diseño. Edite MainActivity.cs y agregue el código siguiente al final del método OnCreate:

var subscribeButton = FindViewById<Button>(Resource.Id.subscribeButton);
subscribeButton.Click += delegate {
    FirebaseMessaging.Instance.SubscribeToTopic("news");
    Log.Debug(TAG, "Subscribed to remote notifications");
};

Este código busca el botón Suscribirse a la notificación en el diseño y asigna su controlador de clics al código que llama a FirebaseMessaging.Instance.SubscribeToTopic, pasando el tema suscrito Noticias. Cuando el usuario pulsa el botón Suscribirse, la aplicación se suscribe al tema de noticias. En la sección siguiente, se enviará un mensaje de tema de noticias desde la GUI de notificaciones de la consola de Firebase.

Envío de un mensaje de tema

Desinstale la aplicación, recompile y ejecútela de nuevo. Haga clic en el botón Suscribirse a las notificaciones:

Botón Suscribirse a notificaciones

Si la aplicación se ha suscrito correctamente, debería ver que la sincronización de temas se realizó correctamente en la ventana de salida del IDE:

Ventana de salida que muestra el mensaje de sincronización correcta del tema

Siga estos pasos para enviar un mensaje de tema:

  1. En la consola de Firebase, haga clic en NUEVO MENSAJE.

  2. En la página Redactar mensaje, escriba el texto del mensaje y seleccione Tema.

  3. En el menú desplegable Tema, seleccione el tema integrado, noticias:

    Seleccionar tema de noticias

  4. En el dispositivo (o emulador) de Android, deje en segundo plano la aplicación al pulsar el botón Información general de Android y tocar la pantalla principal.

  5. Cuando el dispositivo esté listo, haga clic en ENVIAR MENSAJE en la consola de Firebase:

  6. Compruebe la ventana de salida del IDE para ver /topics/news en la salida del registro:

    Se muestra el mensaje de /tema/noticias

Cuando este mensaje se vea en la ventana de salida, el icono de notificación también deberá aparecer en el área de notificación del dispositivo Android. Abra el icono de notificación para ver el mensaje de temas:

El mensaje del tema aparece como una notificación

Si no recibe un mensaje, intente eliminar la aplicación FCMClient en el dispositivo (o emulador) y repita los pasos anteriores.

Notificaciones en primer plano

Para recibir notificaciones en aplicaciones en primer plano, debe implementar FirebaseMessagingService. Este servicio también es necesario para recibir cargas de datos y para enviar mensajes ascendentes. En los ejemplos siguientes se muestra cómo implementar un servicio que extiende FirebaseMessagingService: la aplicación resultante podrá controlar las notificaciones remotas mientras se ejecuta en primer plano.

Implementar FirebaseMessagingService

El servicio FirebaseMessagingService es responsable de recibir y procesar los mensajes de Firebase. Cada aplicación debe hacer una subclase de este tipo e invalidar OnMessageReceived para procesar un mensaje entrante. Cuando una aplicación está en primer plano, la devolución de llamada OnMessageReceived siempre controlará el mensaje.

Nota:

Las aplicaciones solo tienen 10 segundos en los que controlar un mensaje entrante de Firebase Cloud. Cualquier trabajo que tarde más de esto en programarse para la ejecución en segundo plano mediante una biblioteca como Android Job Scheduler o Firebase Job Dispatcher.

Agregue un nuevo archivo denominado MyFirebaseMessagingService.cs y reemplace su código de plantilla por lo siguiente:

using System;
using Android.App;
using Android.Content;
using Android.Media;
using Android.Util;
using Firebase.Messaging;

namespace FCMClient
{
    [Service]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class MyFirebaseMessagingService : FirebaseMessagingService
    {
        const string TAG = "MyFirebaseMsgService";
        public override void OnMessageReceived(RemoteMessage message)
        {
            Log.Debug(TAG, "From: " + message.From);
            Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
        }
    }
}

Tenga en cuenta que el filtro de intención MESSAGING_EVENT debe declararse para que los nuevos mensajes FCM se dirijan a MyFirebaseMessagingService:

[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]

Cuando la aplicación cliente recibe un mensaje de FCM, OnMessageReceived extrae el contenido del mensaje del objeto pasado RemoteMessage llamando a su método GetNotification. A continuación, registra el contenido del mensaje para que se pueda ver en la ventana de salida del IDE:

var body = message.GetNotification().Body;
Log.Debug(TAG, "Notification Message Body: " + body);

Nota:

Si establece puntos de interrupción en FirebaseMessagingService, la sesión de depuración puede o no alcanzar estos puntos de interrupción debido a cómo FCM entrega mensajes.

Enviar otro mensaje

Desinstale la aplicación, recompilela, ejecútela de nuevo y siga estos pasos para enviar otro mensaje:

  1. En la consola de Firebase, haga clic en NUEVO MENSAJE.

  2. En la página Redactar mensaje, escriba el texto del mensaje y seleccione Dispositivo único.

  3. Copie la cadena de token de la ventana de salida del IDE y péguela en el campo token de registro de FCM de la consola de Firebase como antes.

  4. Asegúrese de que la aplicación se ejecuta en primer plano y, a continuación, haga clic en ENVIAR MENSAJE en la consola de Firebase:

    Enviar otro mensaje desde la consola

  5. Cuando se muestre el cuadro de diálogo Revisar mensaje, haga clic en ENVIAR.

  6. El mensaje entrante se registra en la ventana de salida del IDE:

    Cuerpo del mensaje impreso en la ventana de salida

Agregar un remitente de notificación local

En este ejemplo restante, el mensaje FCM entrante se convertirá en una notificación local que se inicia mientras la aplicación se ejecuta en primer plano. Edite MyFirebaseMessageService.cs y agregue las siguientes instrucciones using:

using FCMClient;
using System.Collections.Generic;

Agregue el método siguiente a MyFirebaseMessagingService:

void SendNotification(string messageBody, IDictionary<string, string> data)
{
    var intent = new Intent(this, typeof(MainActivity));
    intent.AddFlags(ActivityFlags.ClearTop);
    foreach (var key in data.Keys)
    {
        intent.PutExtra(key, data[key]);
    }

    var pendingIntent = PendingIntent.GetActivity(this,
                                                  MainActivity.NOTIFICATION_ID,
                                                  intent,
                                                  PendingIntentFlags.OneShot);

    var notificationBuilder = new  NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
                              .SetSmallIcon(Resource.Drawable.ic_stat_ic_notification)
                              .SetContentTitle("FCM Message")
                              .SetContentText(messageBody)
                              .SetAutoCancel(true)
                              .SetContentIntent(pendingIntent);

    var notificationManager = NotificationManagerCompat.From(this);
    notificationManager.Notify(MainActivity.NOTIFICATION_ID, notificationBuilder.Build());
}

Para distinguir esta notificación de las notificaciones en segundo plano, este código marca las notificaciones con un icono que difiere del icono de la aplicación. Agregue el archivo ic_stat_ic_notification.png a Resources/drawable e inclúyalo en el proyecto FCMClient.

El método SendNotification usa NotificationCompat.Builder para crear la notificación y NotificationManagerCompat se usa para iniciar la notificación. La notificación contiene un PendingIntent que permitirá al usuario abrir la aplicación y ver el contenido de la cadena pasada a messageBody. Para obtener más información sobre NotificationCompat.Builder, vea Notificaciones locales.

Llame al método SendNotification al final del método OnMessageReceived:

public override void OnMessageReceived(RemoteMessage message)
{
    Log.Debug(TAG, "From: " + message.From);

    var body = message.GetNotification().Body;
    Log.Debug(TAG, "Notification Message Body: " + body);
    SendNotification(body, message.Data);
}

Como resultado de estos cambios, SendNotification se ejecutará cada vez que se reciba una notificación mientras la aplicación está en primer plano y la notificación aparecerá en el área de notificación.

Cuando una aplicación está en segundo plano, la carga del mensaje determinará cómo se controla el mensaje:

  • Notificación: los mensajes se enviarán a la bandeja del sistema. Aparecerá una notificación local allí. Cuando el usuario pulse en la notificación, se iniciará la aplicación.
  • Datos: los mensajes se controlarán mediante OnMessageReceived.
  • Ambos: los mensajes que tienen una notificación y una carga de datos se entregarán a la bandeja del sistema. Cuando se inicie la aplicación, la carga de datos aparecerá en Extras de Intent que se usó para iniciar la aplicación.

En este ejemplo, si la aplicación está en segundo plano, SendNotification se ejecutará si el mensaje tiene una carga de datos. De lo contrario, se iniciará una notificación en segundo plano (ilustrada anteriormente en este tutorial).

Enviar el último mensaje

Desinstale la aplicación, recompílela, ejecútela de nuevo y siga estos pasos para enviar el último mensaje:

  1. En la consola de Firebase, haga clic en NUEVO MENSAJE.

  2. En la página Redactar mensaje, escriba el texto del mensaje y seleccione Dispositivo único.

  3. Copie la cadena de token de la ventana de salida del IDE y péguela en el campo token de registro de FCM de la consola de Firebase como antes.

  4. Asegúrese de que la aplicación se ejecuta en primer plano y, a continuación, haga clic en ENVIAR MENSAJE en la consola de Firebase:

    Enviar mensaje en primer plano

Esta vez, el mensaje que se registró en la ventana de salida también se empaqueta en una nueva notificación: el icono de notificación aparece en la bandeja de notificaciones mientras la aplicación se ejecuta en primer plano:

Icono de notificación para el mensaje en primer plano

Al abrir la notificación, debería ver el último mensaje que se envió desde la GUI de notificaciones de la consola de Firebase:

Notificación en primer plano que se muestra con el icono de primer plano

Desconectando de FCM

Para cancelar la suscripción a un tema, llame al método UnsubscribeFromTopic en la clase FirebaseMessaging. Por ejemplo, para cancelar la suscripción al tema de noticias suscrito anteriormente, se podría agregar un botón Cancelar suscripción al diseño con el siguiente código de controlador:

var unSubscribeButton = FindViewById<Button>(Resource.Id.unsubscribeButton);
unSubscribeButton.Click += delegate {
    FirebaseMessaging.Instance.UnsubscribeFromTopic("news");
    Log.Debug(TAG, "Unsubscribed from remote notifications");
};

Para anular el registro del dispositivo de FCM por completo, elimine el identificador de instancia llamando al método DeleteInstanceId en la clase FirebaseInstanceId. Por ejemplo:

FirebaseInstanceId.Instance.DeleteInstanceId();

Esta llamada al método elimina el identificador de instancia y los datos asociados a él. Como resultado, se detiene el envío periódico de datos FCM al dispositivo.

Solución de problemas

A continuación se describen los problemas y soluciones alternativas que pueden surgir al usar Firebase Cloud Messaging con Xamarin.Android.

FirebaseApp no se inicializa

En algunos casos, es posible que vea este mensaje de error:

Java.Lang.IllegalStateException: Default FirebaseApp is not initialized in this process
Make sure to call FirebaseApp.initializeApp(Context) first.

Se trata de un problema conocido que puede solucionar limpiando la solución y recompilando el proyecto (Compilar > Limpiar solución, Compilar solución> Recompilar solución).

Resumen

En este tutorial hemos detallado los pasos para implementar notificaciones remotas de Firebase Cloud Messaging en una aplicación de Xamarin.Android. Hemos descrito cómo instalar los paquetes necesarios para las comunicaciones de FCM y explicado cómo configurar el manifiesto de Android para el acceso a los servidores FCM. Se ha proporcionado código de ejemplo que muestra cómo comprobar la presencia de Google Play Services. Hemos demostrado cómo implementar un servicio de escucha de identificador de instancia que negocia con FCM para un token de registro y explicado cómo este código crea notificaciones en segundo plano mientras la aplicación está en segundo plano. También hemos explicado cómo suscribirse a mensajes de tema y proporcionado una implementación de ejemplo de un servicio de escucha de mensajes que se usa para recibir y mostrar notificaciones remotas mientras la aplicación se ejecuta en primer plano.