Compartir a través de


Notificaciones remotas con Google Cloud Messaging

Advertencia

Google anunció que GCM caería en desuso a partir del 10 de abril de 2018. Es posible que los siguientes documentos y proyectos de ejemplo dejen de recibir mantenimiento. Las API de cliente y servidor GCM de Google se quitarán tan pronto como el 29 de mayo de 2019. Google recomienda migrar las aplicaciones de GCM a Firebase Cloud Messaging (FCM). Para obtener más información sobre el desuso y la migración de GCM, consulte Google Cloud Messaging: EN DESUSO.

Para empezar a trabajar con notificaciones remotas mediante Firebase Cloud Messaging con Xamarin, consulte Notificaciones remotas con FCM.

En este tutorial se proporciona una explicación paso a paso de cómo usar Google Cloud Messaging para implementar notificaciones remotas (también llamadas notificaciones push) en una aplicación de Xamarin.Android. Describe las distintas clases que debe implementar para comunicarse con Google Cloud Messaging (GCM), explica cómo establecer los permisos en el manifiesto de Android para el acceso a GCM y muestra la mensajería de un extremo a otro con un programa de prueba de ejemplo.

Introducción a las notificaciones de GCM

En este tutorial, crearemos una aplicación de Xamarin.Android que use Google Cloud Messaging (GCM) para implementar notificaciones remotas (también conocidas como notificaciones push). Implementaremos los distintos servicios de intención y agentes de escucha que usan GCM para la mensajería remota y probaremos nuestra implementación con un programa de línea de comandos que simula un servidor de aplicaciones.

Para poder continuar con este tutorial, debe adquirir las credenciales necesarias para usar los servidores de GCM de Google. Este proceso se explica en Google Cloud Messaging. En concreto, necesitará una clave de API y un id. de emisor para insertar en el código de ejemplo que se presenta en este tutorial.

Usaremos los pasos siguientes para crear una aplicación cliente de Xamarin.Android habilitada para GCM:

  1. Instalar los paquetes adicionales necesarios para las comunicaciones con los servidores de GCM.
  2. Configurar los permisos de aplicación para el acceso a los servidores de GCM.
  3. Implementar código para comprobar la presencia de Google Play Services.
  4. Implementar un servicio de intención de registro que negocia con GCM para un token de registro.
  5. Implementar un servicio de agente de escucha de id. de instancia que escuche las actualizaciones del token de registro de GCM.
  6. Implemente un servicio de agente de escucha de GCM que reciba mensajes remotos del servidor de aplicaciones a través de GCM.

Esta aplicación usará una nueva característica de GCM conocida como mensajería de temas. En la mensajería de temas, el servidor de la aplicación envía un mensaje a un tema, en lugar de a una lista de dispositivos individuales. Los dispositivos que se suscriben a ese tema pueden recibir mensajes de tema como notificaciones push.

Cuando la aplicación cliente esté lista, implementaremos una aplicación de línea de comandos de C# que envía una notificación push a nuestra aplicación cliente a través de GCM.

Tutorial

Para empezar, vamos a crear una nueva solución vacía denominada RemoteNotifications. A continuación, vamos a agregar un nuevo proyecto de Android a esta solución que se basa en la plantilla de la aplicación de Android. Vamos a llamar a este proyecto ClientApp. (Si no está familiarizado con la creación de proyectos de Xamarin.Android, consulte Hola, Android). El proyecto ClientApp contendrá el código de la aplicación cliente de Xamarin.Android que recibe notificaciones remotas a través de GCM.

Agregar los paquetes necesarios

Para poder implementar nuestro código de aplicación cliente, debemos instalar varios paquetes que usaremos para la comunicación con GCM. Además, debemos agregar la aplicación Google Play Store a nuestro dispositivo si aún no está instalada.

Adición del paquete GCM de Google Play Services de Xamarin

Para recibir mensajes de Google Cloud Messaging, el marco de Google Play Services debe estar presente en el dispositivo. Sin este marco, una aplicación Android no puede recibir mensajes de servidores GCM. Google Play Services se ejecuta en segundo plano mientras el dispositivo Android está encendido y escucha silenciosamente los mensajes de GCM. Cuando llegan estos mensajes, Google Play Services convierte los mensajes en intenciones y, a continuación, difunde estas intenciones a las aplicaciones que se han registrado para ellas.

En Visual Studio, haga clic con el botón derecho en Referencias > Administrar paquetes NuGet ...; en Visual Studio para Mac, haga clic con el botón derecho en Paquetes > Agregar paquetes.... Busque Xamarin Google Play Services - GCM e instale este paquete en el proyecto ClientApp:

Installing Google Play Services

Al instalar Xamarin Google Play Services - GCM, se instala automáticamente Xamarin Google Play Services - Base. Si recibe un error, cambie el Valor mínimo de Android del proyecto a destino a un valor distinto de Compilar con la versión del SDK y vuelva a intentar instalar NuGet.

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

using Android.Gms.Common;
using Android.Util;

Esto hace que los tipos del paquete GMS de Google Play Services estén disponibles para nuestro código y agrega la funcionalidad de registro que usaremos para realizar el seguimiento de nuestras transacciones con GMS.

Google Play Store

Para recibir mensajes de GCM, la aplicación Google Play Store debe estar instalada en el dispositivo. (Siempre que se instala una aplicación de Google Play en un dispositivo, Google Play Store también se instala, por lo que es probable que ya esté instalado en el dispositivo de prueba). Sin Google Play, ninguna aplicación Android puede recibir mensajes de GCM. Si aún no tiene instalada la aplicación Google Play Store en el dispositivo, visite el sitio web de Google Play para descargar e instalar Google Play.

Como alternativa, puede usar un emulador de Android que ejecute Android 2.2 o posterior en lugar de un dispositivo de prueba (no es necesario instalar Google Play Store en un emulador de Android). Sin embargo, si usa un emulador, debe usar Wi-Fi para conectarse a GCM y debe abrir varios puertos en el firewall de Wi-Fi, como se explica más adelante en este tutorial.

Establecer el nombre del paquete

En Google Cloud Messaging, se especificó un nombre de paquete para nuestra aplicación habilitada para GCM (este nombre de paquete también actúa como el id. de aplicación asociado a nuestra clave de API e id. del emisor). Vamos a abrir las propiedades del proyecto ClientApp y a establecer el nombre del paquete para esta cadena. En este ejemplo, estableceremos el nombre del paquete en com.xamarin.gcmexample:

Setting the package name

Tenga en cuenta que la aplicación cliente no podrá recibir ningún token de registro de GCM si este nombre de paquete no coincide exactamente con el nombre del paquete que hemos escrito en la consola de Google Developer.

Agregar permisos al manifiesto de Android

Una aplicación Android debe tener configurados los permisos siguientes para poder recibir notificaciones de Google Cloud Messaging:

  • com.google.android.c2dm.permission.RECEIVE: Concede permiso a nuestra aplicación para registrar y recibir mensajes de Google Cloud Messaging. (¿Qué significa c2dm? Significa Cloud to Device Messaging, que es el predecesor de GCM, ahora en desuso. GCM todavía usa c2dm en muchas de sus cadenas de permisos).

  • android.permission.WAKE_LOCK: (Opcional) Impide que la CPU del dispositivo se suspenda mientras escucha un mensaje.

  • android.permission.INTERNET: Concede acceso a Internet para que la aplicación cliente pueda comunicarse con GCM.

  • package_name.permission.C2D_MESSAGE: Registra la aplicación con Android y solicita permiso para recibir exclusivamente todos los mensajes C2D (nube a dispositivo). El prefijo package_name es el mismo que el id. de la aplicación.

Estableceremos estos permisos en el manifiesto de Android. Vamos a editar AndroidManifest.xml y a reemplazar el contenido por el siguiente XML:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR_PACKAGE_NAME"
    android:versionCode="1"
    android:versionName="1.0"
    android:installLocation="auto">
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
    <permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
                android:protectionLevel="signature" />
    <application android:label="ClientApp" android:icon="@drawable/Icon">
    </application>
</manifest>

En el XML anterior, cambie YOUR_PACKAGE_NAME al nombre del paquete del proyecto de aplicación cliente. Por ejemplo, com.xamarin.gcmexample.

Comprobar Google Play Services

En este tutorial, vamos a crear una aplicación sin sistema operativo con un únic TextView en la interfaz de usuario. Esta aplicación no indica directamente la interacción con GCM. En su lugar, inspeccionaremos la ventana de salida para ver cómo nuestra aplicación genera protocolos de enlace con GCM y comprobaremos la bandeja de notificaciones para ver las nuevas notificaciones a medida que llegan.

En primer lugar, vamos a crear un diseño para el área de mensajes. 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>

Guarde Main.axml y ciérrelo.

Cuando se inicia la aplicación cliente, queremos que compruebe que Google Play Services está disponible antes de intentar ponerse en contacto con GCM. Edite MainActivity.cs y reemplace la declaración de variable de instancia count por la siguiente declaración de variable de instancia:

TextView msgText;

A continuación, agregue el método siguiente 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 = "Sorry, 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 el área de mensajes que indica al usuario que descargue un APK desde Google Play Store (o que lo habilite en la configuración del sistema del dispositivo). Dado que queremos ejecutar esta comprobación cuando se inicie la aplicación cliente, agregaremos una llamada a este método al final de OnCreate.

A continuación, reemplace el método OnCreate por el código siguiente:

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);

    SetContentView (Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    IsPlayServicesAvailable ();
}

Este código comprueba la presencia del APK de Google Play Services y escribe el resultado en el área de mensajes.

Vamos a recompilar completamente y ejecutar la aplicación. Debería ver una pantalla similar a la siguiente captura de pantalla:

Google Play Services is available

Si no obtiene este resultado, compruebe que el APK de Google Play Services esté instalado en el dispositivo y que el paquete de Xamarin Google Play Services - GCM se agregue al proyecto ClientApp como se explicó anteriormente. Si recibe un error de compilación, intente limpiar la solución y volver a compilar el proyecto.

A continuación, escribiremos un código para ponerse en contacto con GCM y recuperar el token de registro.

Registro con GCM

Para que la aplicación pueda recibir notificaciones remotas desde el servidor de aplicaciones, debe registrarse con GCM y obtener un token de registro. El trabajo de registrar nuestra aplicación con GCM se controla mediante un IntentService que creamos. Nuestro IntentService realiza las tareas siguientes:

  1. Usa la API InstanceID para generar tokens de seguridad que autorizan a nuestra aplicación cliente a acceder al servidor de aplicaciones. A cambio, se devuelve un token de registro de GCM.

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

  3. Se suscribe a uno o varios canales de temas de notificación.

Después de implementar este IntentService, se probará para ver si se devuelve un token de registro de GCM.

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

using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;

namespace ClientApp
{
    [Service(Exported = false)]
    class RegistrationIntentService : IntentService
    {
        static object locker = new object();

        public RegistrationIntentService() : base("RegistrationIntentService") { }

        protected override void OnHandleIntent (Intent intent)
        {
            try
            {
                Log.Info ("RegistrationIntentService", "Calling InstanceID.GetToken");
                lock (locker)
                {
                    var instanceID = InstanceID.GetInstance (this);
                    var token = instanceID.GetToken (
                        "YOUR_SENDER_ID", GoogleCloudMessaging.InstanceIdScope, null);

                    Log.Info ("RegistrationIntentService", "GCM Registration Token: " + token);
                    SendRegistrationToAppServer (token);
                    Subscribe (token);
                }
            }
            catch (Exception e)
            {
                Log.Debug("RegistrationIntentService", "Failed to get a registration token");
                return;
            }
        }

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

        void Subscribe (string token)
        {
            var pubSub = GcmPubSub.GetInstance(this);
            pubSub.Subscribe(token, "/topics/global", null);
        }
    }
}

En el código de ejemplo anterior, cambie YOUR_SENDER_ID al número de id. de emisor del proyecto de aplicación cliente. Para obtener el id. de emisor del proyecto:

  1. Inicie sesión en Google Cloud Console y seleccione el nombre del proyecto en el menú desplegable. En el panel Información del proyecto que se muestra para el proyecto, haga clic en Ir a la configuración del proyecto:

    Selecting XamarinGCM project

  2. En la página Configuración, busque el Número de proyecto: este es el id. de emisor del proyecto:

    Project number displayed

Queremos iniciar nuestro RegistrationIntentService cuando la aplicación comience a ejecutarse. Edite MainActivity.cs y modifique el método OnCreate para que se inicie RegistrationIntentService después de comprobar la presencia de Google Play Services:

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);

    SetContentView(Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    if (IsPlayServicesAvailable ())
    {
        var intent = new Intent (this, typeof (RegistrationIntentService));
        StartService (intent);
    }
}

Ahora echemos un vistazo a cada sección de RegistrationIntentService para comprender cómo funciona.

En primer lugar, anotamos nuestro RegistrationIntentService con el atributo siguiente para indicar que el sistema no debe crear instancias de nuestro servicio:

[Service (Exported = false)]

El constructor RegistrationIntentService denomina al subproceso de trabajo RegistrationIntentService para facilitar la depuración.

public RegistrationIntentService() : base ("RegistrationIntentService") { }

La funcionalidad principal de RegistrationIntentService reside en el método OnHandleIntent. Examinemos este código para ver cómo registra nuestra aplicación con GCM.

Solicitud de un token de registro

OnHandleIntent llama primero al método InstanceID.GetToken de Google para solicitar un token de registro de GCM. Encapsulamos este código en lock para proteger frente a la posibilidad de que se produzcan varias intenciones de registro simultáneamente; lock garantiza que estas intenciones se procesen secuencialmente. Si no se obtiene un token de registro, se produce una excepción y se registra un error. Si el registro se realiza correctamente, token se establece en el token de registro que obtuvimos de GCM:

static object locker = new object ();
...
try
{
    lock (locker)
    {
        var instanceID = InstanceID.GetInstance (this);
        var token = instanceID.GetToken (
            "YOUR_SENDER_ID", GoogleCloudMessaging.InstanceIdScope, null);
        ...
    }
}
catch (Exception e)
{
    Log.Debug ...

Reenvío del token de registro al servidor de aplicaciones

Si obtenemos un token de registro (es decir, no se produjo ninguna excepción), llamamos a SendRegistrationToAppServer para asociar el token de registro del usuario a la cuenta del lado servidor (si existe) que mantiene nuestra aplicación. Dado que esta implementación depende del diseño del servidor de aplicaciones, aquí se proporciona un método vacío:

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

En algunos casos, el servidor de aplicaciones no necesita el token de registro del usuario; en ese caso, este método se puede omitir. Cuando se envía un token de registro 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.

Suscribirse al tema de la notificación

A continuación, llamamos a nuestro método Subscribe para indicar a GCM que queremos suscribirnos a un tema de notificación. En Subscribe, llamamos a la API GcmPubSub.Subscribe para suscribir nuestra aplicación cliente a todos los mensajes en /topics/global:

void Subscribe (string token)
{
    var pubSub = GcmPubSub.GetInstance(this);
    pubSub.Subscribe(token, "/topics/global", null);
}

El servidor de aplicaciones debe enviar mensajes de notificación a /topics/global si se van a recibir. Tenga en cuenta que el nombre del tema en /topics puede ser cualquiera que desee, siempre y cuando el servidor de aplicaciones y la aplicación cliente acepten dicho nombre. (Aquí, elegimos el nombre global para indicar que queremos recibir mensajes en todos los temas admitidos por el servidor de aplicaciones).

Implementación de un servicio de escucha del id. de instancia

Los tokens de registro son únicos y seguros; sin embargo, es posible que la aplicación cliente (o GCM) tenga que actualizar el token de registro en caso de reinstalación de la aplicación o de un problema de seguridad. Por este motivo, debemos implementar un InstanceIdListenerService que responda a las solicitudes de actualización de tokens de GCM.

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

using Android.App;
using Android.Content;
using Android.Gms.Gcm.Iid;

namespace ClientApp
{
    [Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
    class MyInstanceIDListenerService : InstanceIDListenerService
    {
        public override void OnTokenRefresh()
        {
            var intent = new Intent (this, typeof (RegistrationIntentService));
            StartService (intent);
        }
    }
}

Anote InstanceIdListenerService con el atributo siguiente para indicar que el sistema no va a crear instancias del servicio y puede recibir solicitudes de actualización del token de registro de GCM (también denominadas id. de instancia):

[Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]

El método OnTokenRefresh de nuestro servicio inicia RegistrationIntentService para que pueda interceptar el nuevo token de registro.

Registro de prueba con GCM

Vamos a recompilar completamente y ejecutar la aplicación. Si recibe correctamente un token de registro de GCM, el token de registro debe mostrarse en la ventana de salida. Por ejemplo:

D/Mono    ( 1934): Assembly Ref addref ClientApp[0xb4ac2400] -> Xamarin.GooglePlayServices.Gcm[0xb4ac2640]: 2
I/RegistrationIntentService( 1934): Calling InstanceID.GetToken
I/RegistrationIntentService( 1934): GCM Registration Token: f8LdveCvXig:APA91bFIsjUAbP-V8TPQdLR89qQbEJh1SYG38AcCbBUf34z5gSdUc5OsXrgs93YFiGcRSRafPfzkz23lf3-LvYV1CwrFheMjHgwPeFSh12MywnRIhz

Controlar los mensajes de bajada

El código que hemos implementado hasta ahora es solo código "configurado"; comprueba si Google Play Services está instalado y negocia con GCM y el servidor de aplicaciones para preparar nuestra aplicación cliente para recibir notificaciones remotas. Sin embargo, todavía tenemos que implementar el código que realmente recibe y procesa los mensajes de notificación de bajada. Para ello, debemos implementar un servicio de agente de escucha de GCM. Este servicio recibe mensajes del tema del servidor de aplicaciones y los difunde localmente como notificaciones. Después de implementar este servicio, crearemos un programa de prueba para enviar mensajes a GCM para que podamos ver si nuestra implementación funciona correctamente.

Agregar un icono de notificación

Vamos a agregar primero un pequeño icono que aparecerá en el área de notificación cuando se inicie la notificación. Puede copiar este icono en el proyecto o crear su propio icono personalizado. Asignaremos un nombre al archivo de icono ic_stat_button_click.png y lo copiaremos en la carpeta Resources/drawable. No olvide usar Agregar > Elemento existente... para incluir este archivo de icono en el proyecto.

Implementación de un servicio de escucha de GCM

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

using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Android.Util;

namespace ClientApp
{
    [Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
    public class MyGcmListenerService : GcmListenerService
    {
        public override void OnMessageReceived (string from, Bundle data)
        {
            var message = data.GetString ("message");
            Log.Debug ("MyGcmListenerService", "From:    " + from);
            Log.Debug ("MyGcmListenerService", "Message: " + message);
            SendNotification (message);
        }

        void SendNotification (string message)
        {
            var intent = new Intent (this, typeof(MainActivity));
            intent.AddFlags (ActivityFlags.ClearTop);
            var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);

            var notificationBuilder = new Notification.Builder(this)
                .SetSmallIcon (Resource.Drawable.ic_stat_ic_notification)
                .SetContentTitle ("GCM Message")
                .SetContentText (message)
                .SetAutoCancel (true)
                .SetContentIntent (pendingIntent);

            var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
            notificationManager.Notify (0, notificationBuilder.Build());
        }
    }
}

Echemos un vistazo a cada sección de nuestro GcmListenerService para comprender cómo funciona.

En primer lugar, anotamos GcmListenerService con un atributo para indicar que el sistema no debe crear instancias de este servicio y se incluye un filtro de intención para indicar que recibe mensajes de GCM:

[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]

Cuando GcmListenerService recibe un mensaje de GCM, se invoca el método OnMessageReceived. Este método extrae el contenido del mensaje Bundle pasado, registra el contenido del mensaje (para que podemos verlo en la ventana de salida) y llama a SendNotification para iniciar una notificación local con el contenido del mensaje recibido:

var message = data.GetString ("message");
Log.Debug ("MyGcmListenerService", "From:    " + from);
Log.Debug ("MyGcmListenerService", "Message: " + message);
SendNotification (message);

El método SendNotification usa Notification.Builder para crear la notificación y, a continuación, usa NotificationManager para iniciar la notificación. De hecho, esto convierte el mensaje de notificación remota en una notificación local que se presentará al usuario. Para obtener más información sobre el uso de Notification.Builder y NotificationManager, vea Notificaciones locales.

Declarar el receptor en el manifiesto

Para poder recibir mensajes de GCM, debemos declarar el agente de escucha de GCM en el manifiesto de Android. Vamos a editar AndroidManifest.xml y reemplazar la sección <application> por el siguiente XML:

<application android:label="RemoteNotifications" android:icon="@drawable/Icon">
    <receiver android:name="com.google.android.gms.gcm.GcmReceiver"
              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="YOUR_PACKAGE_NAME" />
        </intent-filter>
    </receiver>
</application>

En el XML anterior, cambie YOUR_PACKAGE_NAME al nombre del paquete del proyecto de aplicación cliente. En nuestro ejemplo de tutorial, el nombre del paquete es com.xamarin.gcmexample.

Echemos un vistazo a lo que hace cada configuración de este XML:

Configuración Descripción
com.google.android.gms.gcm.GcmReceiver Declara que nuestra aplicación implementa un receptor GCM que captura y procesa los mensajes de notificación push entrantes.
com.google.android.c2dm.permission.SEND Declara que solo los servidores GCM pueden enviar mensajes directamente a la aplicación.
com.google.android.c2dm.intent.RECEIVE La publicidad de filtro de intención con la que nuestra aplicación controla los mensajes de difusión desde GCM.
com.google.android.c2dm.intent.REGISTRATION La publicidad de filtro de intención con la que nuestra aplicación controla las nuevas intenciones de registro (es decir, hemos implementado un servicio de escucha del id. de instancia).

Como alternativa, puede decorar GcmListenerService con estos atributos en lugar de especificarlos en XML; aquí se especifican en AndroidManifest.xml para que los ejemplos de código sean más fáciles de seguir.

Creación de un emisor de mensajes para probar la aplicación

Vamos a agregar un proyecto de aplicación de consola de escritorio de C# a la solución que llamaremos MessageSender. Usaremos esta aplicación de consola para simular un servidor de aplicaciones: enviará mensajes de notificación a ClientApp a través de GCM.

Agregar el paquete de Json.NET

En esta aplicación de consola, estamos creando una carga JSON que contiene el mensaje de notificación que queremos enviar a la aplicación cliente. Usaremos el paquete Json.NET en MessageSender para facilitar la compilación del objeto JSON requerido por GCM. En Visual Studio, haga clic con el botón derecho en Referencias > Administrar paquetes NuGet...; en Visual Studio para Mac, haga clic con el botón derecho en Paquetes > Agregar paquetes....

Vamos a buscar el paquete Json.NET e instalarlo en el proyecto:

Installing the Json.NET package

Agregar una referencia a System.Net.Http

También es necesario agregar una referencia a System.Net.Http para que podamos crear instancias de HttpClient para enviar el mensaje de prueba a GCM. En el proyecto MessageSender, haga clic con el botón derecho en Referencias > Agregar referencia y desplácese hacia abajo hasta que vea System.Net.Http. Coloque una marca de verificación junto a System.Net.Http y haga clic en Aceptar.

Implementar un código que envíe el mensaje de prueba

En MessageSender, edite Program.cs y reemplace el contenido por el código siguiente:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace MessageSender
{
    class MessageSender
    {
        public const string API_KEY = "YOUR_API_KEY";
        public const string MESSAGE = "Hello, Xamarin!";

        static void Main (string[] args)
        {
            var jGcmData = new JObject();
            var jData = new JObject();

            jData.Add ("message", MESSAGE);
            jGcmData.Add ("to", "/topics/global");
            jGcmData.Add ("data", jData);

            var url = new Uri ("https://gcm-http.googleapis.com/gcm/send");
            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/json"));

                    client.DefaultRequestHeaders.TryAddWithoutValidation (
                        "Authorization", "key=" + API_KEY);

                    Task.WaitAll(client.PostAsync (url,
                        new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
                            .ContinueWith(response =>
                            {
                                Console.WriteLine(response);
                                Console.WriteLine("Message sent: check the client device notification tray.");
                            }));
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Unable to send GCM message:");
                Console.Error.WriteLine(e.StackTrace);
            }
        }
    }
}

En el código anterior, cambie YOUR_API_KEY a la clave de API del proyecto de aplicación cliente.

Este servidor de aplicaciones de prueba envía el siguiente mensaje con formato JSON a GCM:

{
  "to": "/topics/global",
  "data": {
    "message": "Hello, Xamarin!"
  }
}

GCM, a su vez, reenvía este mensaje a la aplicación cliente. Vamos a compilar MessageSender y a abrir una ventana de consola donde podamos ejecutarlo desde la línea de comandos.

¡Inténtelo!

Ahora estamos listos para probar nuestra aplicación cliente. Si usa un emulador o si el dispositivo se comunica con GCM a través de Wi-Fi, debe abrir los siguientes puertos TCP en el firewall para que los mensajes de GCM se realicen a través de: 5228, 5229 y 5230.

Inicie la aplicación cliente y observe la ventana de salida. Después de que RegistrationIntentService recibe correctamente el token de registro de GCM, la ventana de salida debe mostrar el token con una salida de registro similar a la siguiente:

I/RegistrationIntentService(16103): GCM Registration Token: eX9ggabZV1Q:APA91bHjBnQXMUeBOT6JDiLpRt8m2YWtY ...

En este momento, la aplicación cliente está lista para recibir un mensaje de notificación remota. Desde la línea de comandos, ejecute el programa MessageSender.exe para enviar un mensaje de notificación "Hola, Xamarin" a la aplicación cliente. Si aún no ha compilado el proyecto MessageSender, hágalo ahora.

Para ejecutar MessageSender.exe en Visual Studio, abra un símbolo del sistema, cambie al directorio MessageSender/bin/Debug y ejecute el comando directamente:

MessageSender.exe

Para ejecutar MessageSender.exe en Visual Studio para Mac, abra una sesión de Terminal, cambie al directorio MessageSender/bin/Debug y use mono para ejecutar MessageSender.exe

mono MessageSender.exe

El mensaje puede tardar hasta un minuto en propagarse a través de GCM y volver a la aplicación cliente. Si el mensaje se recibe correctamente, deberíamos ver una salida similar a la siguiente en la ventana de salida:

D/MyGcmListenerService(16103): From:    /topics/global
D/MyGcmListenerService(16103): Message: Hello, Xamarin!

Además, debe observar que aparece un nuevo icono de notificación en la bandeja de notificaciones:

Notification icon appears on device

Al abrir la bandeja de notificaciones para ver las notificaciones, debería ver nuestra notificación remota:

Notification message is displayed

¡Enhorabuena! La aplicación ha recibido su primera notificación remota.

Tenga en cuenta que ya no se recibirán los mensajes de GCM si la aplicación está detenida por fuerza. Para reanudar las notificaciones después de una detención forzada, la aplicación debe reiniciarse manualmente. Para obtener más información sobre esta directiva de Android, consulte Iniciar controles en aplicaciones detenidas y esta publicación de desbordamiento de pila.

Resumen

En este tutorial se detallaron los pasos para implementar notificaciones remotas en una aplicación de Xamarin.Android. Se describe cómo instalar los paquetes adicionales necesarios para las comunicaciones de GCM y se explica cómo configurar los permisos de aplicación para acceder a los servidores de GCM. Se proporcionó un código de ejemplo que muestra cómo comprobar la presencia de Google Play Services, cómo implementar un servicio de escucha del id. de instancia y un servicio de escucha de intención de registro que negocia con GCM para un token de registro y cómo implementar un servicio de escucha de GCM que recibe y procesa los mensajes de notificación remota. Por último, hemos implementado un programa de prueba de línea de comandos para enviar notificaciones de prueba a nuestra aplicación cliente a través de GCM.