Microsoft Azure Notification Hubs

Con la salida de Mobile Services en la plataforma Microsoft Azure se nos dio la posibilidad de crear de una forma rápida el back-end de nuestras aplicaciones orientadas a dispositivos móviles. Dentro de este servicio se resuelven tres pilares: datos, autenticación y notificaciones push. Sin embargo, es posible que nuestro back-end ya esté desarrollado y sólo necesitemos el envío de notificaciones pero, con la cantidad de dispositivos y plataformas de notificación en el mercado, esta tarea puede resultar compleja de manejar. Normalmente, cuando trabajamos con notificaciones, los pasos a seguir son los siguientes:

  1. Informarnos sobre la plataformas con las que queremos trabajar: Windows Store, Windows Phone, iOS, Android, etcétera. Cada una de ellas necesita una configuración previa, credenciales, cuenta de desarrollo, diferentes plantillas para las notificaciones, etcétera.
  2. La aplicación del cliente debe registrarse en el PNS (Platform Notification Service) acorde con su sistema operativo. El objetivo de este registro es que la aplicación cliente obtenga lo que se conoce como handle que, dependiendo del PNS, puede ser un token, channelURIs, registrationIds (No, no hay un sistema común).
  3. Una vez que los dispositivos están registrados, la aplicación de back-end se encarga de enviar notificaciones a los diferentes PNS para que, a su vez, estos las envíen a los respectivos dispositivos, ya sean a usuarios específicos o grupos.

PNS

Realizar esta gestión por cada una de las plataformas con las que queremos trabajar puede resultar bastante tedioso y es el principal motivo por el que aparece Notification Hubs.

Configuración

No debemos olvidar que este servicio pertenece a Service Bus, por lo que la forma de encontrarlo a través del portal es dentro de la misma sección:

Create Notification Hubs Services

Una vez que tenemos el servicio dado de alta, el primer paso es configurar aquellos PNS que vayamos a utilizar. Para ello, accedemos al servicio NOTIFICATION HUBS y dentro de él al apartado CONFIGURE, donde podremos añadir la configuración para cada una de las plataformas. Si no estáis familiarizados con el proceso, os recomiendo que utilicéis el botón inferior de ayuda para orientaros:

Configure notification hubs

Una vez que tenemos configurado al menos uno de ellos, los pasos son en principio dos: registro de dispositivos y envío de notificaciones.

Registro de dispositivos

Debido a que la forma de registro difiere entre una plataforma y otra, es necesario realizar esta operación por separado, ya que Notification Hubs debe saber a qué PNS debe dirigirse para cada caso en concreto. Para ello, es necesario saber a qué plataforma corresponde el dispositivo que queremos registrar. En el caso por ejemplo de Windows Store, podríamos realizar la operación de la siguiente manera:

En nuestra aplicación Windows Store, añadimos el siguiente paquete a través de Nuget: Install-Package WindowsAzure.Messaging.Managed

var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

var hub = new NotificationHub("<hub name>", "<connection string with listen access>");
var result = await hub.RegisterNativeAsync(channel.Uri);

Básicamente lo que se hace es:

  1. Recuperar el handle para Windows Store. En este caso se trata de un ChannelURI.
  2. Creamos la conexión con nuestro servicio de Notification Hub. Como se ve en el código, se necesita la cadena de conexión con acceso únicamente a la escucha de notificaciones. ¿Esto qué significa? Por defecto tenemos dos tipos de conexiones con el servicio: control total (lo suele utilizar la aplicación de back-end, que se encarga del envío de notificaciones) y sólo escucha (sólo se permite el registro y la recepción mensajes). Se puede encontrar un botón llamado CONNECTION INFORMATION en la parte inferior de la sección DASHBOARD del servicio donde nos facilita ambas conexiones.
  3. Por último, a través de la instancia de NotificationHub realizamos el registro de manera asíncrona al PNS de Windows Store, utilizando el ChannelURI recuperado anteriormente.

En el caso de Windows Store, podemos comprobar en este tutorial cómo se asocia una aplicación con una dada de alta en Windows Store y cómo se habilitan las notificaciones toast. A partir del mismo podemos ver el resto de tutoriales para los diferentes dispositivos.

Es recomendable que el registro de los dispositivos se realice en el lado del back-end, ya que normalmente sería necesaria la autenticación y autorización previa del usuario para determinar si puede o no registrar a nuestro servicio de notificaciones. En este otro tutorial podéis encontrar una simulación de este caso.

Este es el ejemplo más simple: Registro los dispositivos en su correspondiente PNS y con ello espero la recepción de cualquier mensaje enviado desde Notification Hubs.

Envío de notificaciones

Una vez realizado el registro, ya estamos listos para añadir en Notification Hubs los mensajes para nuestros usuarios. De esta parte se encarga nuestro back-end y debe tener en cuenta que cada plataforma tiene su propio formato o plantillas para los mensajes que se muestran en los diferentes dispositivos, por lo que es necesario enviar la información con el formato esperado por el PNS.

Cuando trabajamos con el back-end en .NET/Visual Studio, debemos hacer uso del siguiente paquete de Nuget: Install-Package WindowsAzure.ServiceBus.

Si quisiéramos enviar una notificación a los dispositivos de Windows Store, podríamos utilizar por ejemplo la plantilla ToastText01.

NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<connection string with full access>", "<hub name>");

var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">Hello from Notification Hubs!</text></binding></visual></toast>";
await hub.SendWindowsNativeNotificationAsync(toast);

Para dispositivos iOS, el formato sería distinto:

 var alert = "{"aps":{"alert":"Hello from Notification Hubs"}, "inAppMessage":"Hello geeks!"}";

await hubClient.SendAppleNativeNotificationAsync(alert);

Este mensaje será enviado a todos los dispositivos que se hayan registrado de la forma mencionada en el punto anterior. Además será necesario hacer el envío por cada uno de los PNS con los que estemos trabajando, ya que cada uno de ellos necesita una plantilla totalmente distinta, o quizás necesitemos que cada sistema operativo tenga un mensaje totalmente diferente.

Tags

Una de las primeras preguntas que nos puede venir a la cabeza es ¿Cómo redirijo un mensaje a un único usuario? ¿O a un grupo? ¿Puedo de alguna manera diferenciar las notificaciones y sus receptores?. La respuesta para todo ello tiene que ver con lo que se conoce como tags. Estas etiquetas pueden ser desde lo más simple hasta las expresiones más complejas, pero en cualquier caso son simplemente strings: el id del usuario, el tipo de plataforma, categorías de noticias, ubicaciones, etcétera. Gracias a ello podemos granular desde un único usuario hasta un conjunto de ellos. La forma de trabajar con tags es la siguiente:

Lo primero que debemos hacer es incluir el tag/tags a los que queremos que el usuario se suscriba durante el registro del dispositivo.

Ejemplo en Windows Store:

var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

var hub = new NotificationHub("<hub name>", "<connection string with listen access>");
var result = await hub.RegisterNativeAsync(channel.Uri, new[] {"gis","spain"});

Como podemos ver, el método de registro es el mismo que se mostró anteriormente, sólo que en este caso se añade un segundo parámetro: un IEnumerable de strings correspondiente con los tags o suscripciones que tiene el dispositivo de ese usuario (podría tener diferentes dispositivos con diferentes tags, por ejemplo). En el código anterior los tags a los que el dispositivo estaría registrado podrían ser por ejemplo el nombre usuario (“gis”) y la ubicación (“spain”).

Por otro lado, desde el back-end podríamos enviar mensajes según la lógica de nuestro negocio a estos tags, con el objetivo de que sólo lo reciban aquellos dispositivos suscritos a los mismos:

                    // Create notifications for both Windows Store and iOS platforms.
                    var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" +
                        notificationText + "</text></binding></visual></toast>";
                    var alert = "{"aps":{"alert":"" + notificationText +
                        ""}, "inAppMessage":"" + notificationText + ""}";

                    // Send a notification to the logged-in user on both platforms.
                    await hubClient.SendWindowsNativeNotificationAsync(toast, "gis");
                    await hubClient.SendAppleNativeNotificationAsync(alert, "spain");

En el ejemplo anterior se muestra dos tipos de alertas: una para Windows Store y otra para iOS. En el momento de realizar el envío al servicio de Notification Hubs pasamos la plantilla que vamos a utilizar y además los tags a los que necesitamos que el usuario esté suscrito para que reciba dicha notificación. En el caso de Windows le pasamos el tag “gis” y en el segundo de ellos “spain”. Según la lógica de nuestro negocio, el primer mensaje sólo sería recibido por el usuario “gis” y el segundo mensaje por todos aquellos usuarios que estuvieran en España. Por pensar en un caso más complejo, si quisiéramos por ejemplo que el primer mensaje sólo llegara al dispositivo del usuario gis que estuviera registrado dentro de España, podríamos utilizar lo que se conoce como tag expression, que no es más que la concatenación de varios valores, como ejemplo: “gis_spain”, “gis_uk”, etcétera.

Templates

Otra de las funcionalidades que acepta el servicio es el uso de plantillas. Las mismas pueden ser utilizadas con distintos fines:

  • Una aplicación agnóstica a la plataforma donde envía los mensajes. Nos permite enviar mensajes de forma masiva a todas las PNSs configurados.
  • Personalización de las notificaciones.
  • Facilita la localización.

Como ya hemos visto anteriormente, cada plataforma utiliza sus propio formato (JSON para APNS, XML para WNS, etcétera). Este requerimiento fuerza al back-end a crear diferentes payloads dependiendo del dispositivo, lo que hace que se ligue a una plantilla en concreto que puede diferir según la versión del sistema operativo, suponiendo un problema para el receptor. La forma de resolverlo es creando templates desde el lado del cliente y registrándolas en el servicio. De este modo, el back-end sólo deberá enviar los parámetros establecidos en esas templates para que se muestre de la manera correcta.

Este podría ser un ejemplo:

<toast>
  <visual>
    <binding template="ToastText01">
      <text id="1">$(message)</text>
    </binding>
  </visual>
</toast>
{"aps":{"alert":"$(message)"}}
Es importante saber que las templates no aceptan strings, sino que debería incluirse dentro de llaves: {‘Hi, ‘ + $(message)}

Los clientes deberían de registrar la plantilla, en el caso de Windows Store, de la siguiente manera:

await hub.CreateWindowsTemplateRegistrationAsync(channelUri, template, tags);

Existe un método para cada PNS. En el caso de Windows Store se pasa el channelUri correspondiente, la plantilla en si y los tags a los que se está suscrito.

Una vez registradas tantas plantillas como queramos, ya podemos hacer uso de Notification Hubs de la siguiente manera:

                var notification = new Dictionary<string, string> { { "message", "Hello, " + tag } };
                await hubClient.SendTemplateNotificationAsync(notification, tag);

Como se puede ver, no hacemos distinción entre iOS (APNS) o Windows Store (WNS). Simplemente enviamos un Diccionario de strings con la clave, en este caso “message”, correspondiente con el parámetro incluido en la plantilla y el contenido por el cual queremos que sea reemplazado. Por último, utilizamos SendTemplateNotificationAsync para indicar que vamos a hacer el envío de los valores de una template, donde le pasamos los parámetros y el tag/s al que tienen que estar suscritos los dispositivos. Es posible registrar más de una template, por ejemplo una para alertas, otra para avisos, etcétera.

Espero que haya sido de utilidad.

¡Saludos!