Los smartphone actuales tienen mayor potencia que muchos ordenadores de hace solo unos años, y además tienen la característica fundamental de que están siempre conectados a Internet, bien a través de 3G o de WiFi. Eso los hace muy adecuados para todo tipo de aplicaciones que consuman información en tiempo real (o “casi-real”), así como la implementación de servicios que impliquen el consumo de información muy actualizada (noticias, avisos, mensajes, etc…).

Por ejemplo, Windows Phone dispone de 3 tipos de notificaciones: las “Tostadas” (Toast) que son mensajes informativos que saltan en cualquier momento, las de “Baldosas” (Tile) que se muestran directamente en los rectángulos que representan tu aplicación en la portada, y las “raw” que se reciben directamente en la aplicación cuando está en ejecución. En esta figura la franja verde de la parte superior es una notificación Toast y en las baldosas podemos ver numeritos que se corresponden con notificaciones Tile:

WP7Notificaciones

En el caso de iOS para iPhone y iPad, las notificaciones son similares y disponemos de diálogos aún más visibles (equivalentes a los Toast) así como numeritos en los iconos equivalentes a los Tile (por ejemplo el correo en la parte inferior de esta figura):

iPhoneNotificaciones

El problema de la batería

Si desarrollas aplicaciones para móviles y quieres mostrar al usuario avisos e información en tiempo real dependientes de información externa, tienes básicamente dos formas teóricas de conseguirlo:

  1. Si el usuario está usando tu aplicación puedes mostrar las notificaciones que creas convenientes, pues tienes toda su atención. Si la información se genera en Internet (como es habitual) puedes realizar llamadas periódicas a un servicio externo que te devuelva la información necesaria (por ejemplo, que te muestre las últimas noticias o lo que sea que consumes).
  2. Si tu aplicación no está siendo utilizada podrías tener una especie de servicio o “demonio” ejecutándose en el teléfono que realice comprobaciones periódicamente, y si hay algo que notificar que muestre un diálogo, actualice un panel de información o directamente lance tu aplicación.

El problema con la primera estrategia es que el usuario no puede estar usando tu aplicación todo el rato, por lo que no puedes depender de esto para mostrar alertas, que por definición, pueden llegar en cualquier momento, cuando son necesarias.

La segunda estrategia tiene un problema fundamental: ningún sistema operativo para móviles que se precie te va a permitir hacer algo así.

Imagínate que el sistema operativo lo permitiera: no sólo tu aplicación, sino potencialmente docenas de ellas, estarían lanzando peticiones en segundo plano a servicios de Internet, con la cadencia que ellas mismas consideraran, es decir, potencialmente decenas de conexiones cada minuto a Internet. El resultado: tu batería agotada en un par de horas y de paso tu tarifa plana (que no es plana, sino ondulada pues tiene un límite) agotada en pocos días.

Otros efectos secundarios serían mucha memoria consumida, elevada demanda del procesador, conexiones lentas, fallos de conectividad, lentitud del terminal… Y como los usuarios no saben si eso es culpa de las aplicaciones o del sistema operativo, el resultado adicional es que dirían que “iPhone/WP7 es una porquería”, algo que –por supuesto- no le interesa a ningún fabricante.

Conclusión: tu aplicación no puede enviar alertas ni notificaciones por si misma.

Servicios PUSH de notificaciones

Dado que está claro que los teléfonos lo permiten: ¿cómo es posible conseguir esta funcionalidad en una de nuestras aplicaciones si tenemos la limitación anterior?. Pues todos los sistemas operativos funcionan de una manera similar, y para conseguirlo utilizan una arquitectura distribuida en la que tu teléfono, su servicio y un servicio que tú debes programar tienen que trabajar en armonía. Es lo que voy a explicar teóricamente en este post.

Aunque cada S.O. tiene sus particularidades, todos funcionan de una manera similar, así que comprendiendo esta arquitectura nos servirá para trabajar en cualquier plataforma.

Existen tres piezas del mecanismo que deben trabajar conjuntamente para que todo el sistema funcione: el terminal, un servicio propio que debemos programar y un servicio de notificaciones que proporciona el fabricante (Microsoft o Apple). El servicio propio se encargará de lanzar las notificaciones cuando sea necesario (tendremos que programarlo, claro está), usando para ello como intermediario el servicio del fabricante.

El siguiente esquema ilustra el funcionamiento general de este tipo de sistemas:

ArquitecturaPUSH

· Paso 1: Primeramente nuestra aplicación debe indicar al sistema operativo que desea recibir notificaciones y alertas desde el servicio PUSH, para lo cual existe una API concreta en cada plataforma. Se hace una llamada a un método especial que se conecta al servicio PUSH del fabricante para registrar el terminal y la aplicación (paso 1 en la figura). Esta operación sólo se lleva a cabo una vez, y luego ya no es necesaria.

· Paso 2: Como resultado de esta operación el servicio devuelve a nuestra aplicación una URI (identificador universal de recursos). Ésta es única para ese teléfono y esa aplicación, lo cual nos asegura que podremos enviar mensajes específicamente a ese usuario y no a otros. En el caso de Apple no es exactamente una URI sino un token o testigo único, pero a efectos prácticos es lo mismo.

· Paso 3: Esa URI que hemos obtenido es necesario pasársela al servicio que hemos creado y que tendremos disponible en Internet. A partir de este momento nuestro servicio sabe cómo debe comunicar las nuevas alertas y eventos al servicio del fabricante.

· Paso 4: Nuestro servicio se encarga de recuperar la información que necesitemos notificar, bien sea un nuevo mensaje recibido, un resumen de noticias, etc… dependerá de la utilidad de nuestra aplicación. Es este servicio el que se encarga de verdad de estar trabajando en segundo plano para obtener la información, dado que no podemos tenerlo en el teléfono estará en Internet. Para este tipo de desarrollos se prestan muy bien los servicios en la nube como Azure que además ofrecen sistemas de colas muy apropiados para estas aplicaciones.

Bien, cuando se determina que es necesario enviar una notificación se hace una llamada a la API del servicio PUSH del fabricante. A este servicio se le pasa la URI obtenida en el paso 3 y una breve información de forma que se enviará la notificación al terminal correcto pues la URI,  por definición, es única.

Si la aplicación ya no existe (porque el usuario la desinstaló) en el caso de Microsoft la llamada devuelve un código específico para indicarlo. En el caso de Apple existe un “servicio de Feedback” que debemos consultar periódicamente y que contiene los tokens que han sido eliminados (por haber desaparecido la aplicación) y a las cuales ya no debemos notificar más. Es más incomodo.

Existe un límite en cuanto al tamaño de la información que se le puede pasar al servicio PUSH. En el caso de iOS es de 256 bytes, mientras que en el de Windows Phone es de cuatro veces más (1024 bytes).

También existe un límite por defecto en el número de peticiones que nuestro servicio puede enviar al servicio PUSH del fabricante que en el caso de Microsoft son 500 notificaciones  al día para una misma URI. No dispongo de esa información en el caso de Apple.

· Paso 5: el servicio PUSH recibe la notificación desde nuestro servicio y la encola para ser enviada al terminal. Si éste está conectado se envía inmediatamente, si no permanece en la cola a la espera de que vuelva a establecerse la conexión para esa URI.

Si el terminal no está conectado y se acumulan varias notificaciones para la misma aplicación el servicio PUSH sólo envía la última para no saturar al usuario, así que pueden perderse notificaciones concretas. La conexión entre el terminal y el servicio está asegurada mediante TSL. Eso es así tanto en Microsoft como en Apple.

Los servicios de notificación PUSH funcionan creando un único conducto de comunicación entre el dispositivo móvil y el servicio del fabricante en la nube. Este conducto se constituye a través de un socket “raw” que no se cierra pero que apenas consume recursos y sólo transfiere información estrictamente cuando es necesario. Es el típico modelo de suscripción/publicación o PUSH, que contrasta frente al modelo de petición/respuesta habitual en la Web en que, en este caso y como hemos visto, es el servidor el que envía la información al cliente cuando es necesario y no depende de que éste la solicite (no hay peticiones desde el terminal). En la wikipedia hay un pequeño artículo al respecto si quieres aprender un poco sobre este tipo de conexiones.

Gracias a ello sólo es necesario un canal abierto entre el teléfono y el servicio para recibir todas las notificaciones. El S.O. del móvil se encarga de notificar a la aplicación apropiada del modo adecuado según el tipo de notificación recibido por el canal y su contenido. De esta forma apenas se consumen datos y los escasos recursos del teléfono (rendimiento, memoria y batería) se preservan perfectamente.

Como vemos es un método que complica un poco la vida a los programadores, pero que a cambio permite disponer de un servicio casi en tiempo real sin poner en peligro la estabilidad de los terminales.

Si estás interesado en conocer más sobre el funcionamiento en la práctica de estos servicios de notificación aquí te dejo los enlaces a la documentación concreta en Microsoft y en Apple.

De regalo: cómo actualizar automáticamente un Tile sin usar PUSH

Si lo anterior te parece muy complejo de desarrollar (al fin y al cabo implica no sólo saber de desarrollo para el terminal sino también desarrollo Web y/o para la nube), en el caso de Windows Phone existe la posibilidad de obtener actualizaciones automáticas de baldosas (Tiles) sin necesidad de desarrollar un servicio ni pasar por el intermediario PUSH.

Se trata de definir una URL que devuelve una imagen que se usará automáticamente para dibujar el Tile. El propio teléfono se encargará de actualizarla con la periodicidad que indiquemos. Esta periodicidad no puede ser cualquiera sino únicamente una de los cuatro valores de la enumeración UpdateInterval, a saber: cada hora, cada día, cada semana o cada mes. O sea, como mínimo cada hora, menos no se puede.

Por lo tanto no nos sirve para actualizaciones en tiempo real, pero sí que será suficiente para otros tipos de aplicaciones que no necesiten esa inmediatez.

Otra limitación es que la imagen debe pesar menos de 80 KB y además debe tardar en cargar menos de 15 segundos (si tenemos muchos usuarios deberemos tener un ancho de banda suficiente para asegurar esto).

Aún así me parece una opción muy interesante y a tener en cuenta. Es además, muy sencilla de implementar.

¡Espero que te resulte útil!

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor

Escrito por un humano, no por una IA