Notificaciones con Polymer

  • Por
Cómo suscribirse a notificaciones de Chrome que podrá recibir una aplicación web, una asombrosa característica de las Progressive Web Apps sencilla de implementar con Polymer.

Una de las asombrosas características de las denominadas Progressive Web Apps es la posibilidad de enviar notificaciones a un usuario. Esas notificaciones push son como las que recibimos con el móvil con las apps que tenemos instaladas, pero en este caso asociadas a un sitio web.

La gracia de las notificaciones es que se pueden recibir incluso cuando un usuario no está visitando la web, lo que las hace una herramienta excelente para retener y recuperar usuarios o comunicar cualquier tipo de evento importante que queremos que sea conocido aunque el usuario no esté visitando tu sitio en ese momento.

Funcionan tanto en el móvil como en ordenadores de escritorio, aunque en este momento solo para el navegador Chrome. Posiblemente cuando leas este artículo esto haya cambiado, pues es un estándar que está siendo definido. Firefox ya tiene su implementación (no compatible todavía con el proceso que vamos a describir).

Este tema de las notificaciones no es un asunto trivial, pues intervienen varios actores que debemos de conocer y además hay que cubrir un ciclo determinado, de suscripción, envío de notificación, etc. En este artículo pretendemos hacer las cosas sencillas, a modo de demostración. Es por ello que vamos a usar Polymer y Firebase, porque realmente nos acortan y simplifican varios pasos importantes.

El código completo de nuestro ejercicio lo encuentras en Github: https://github.com/deswebcom/polynotif

Nota: Necesitarás conocimientos de Polymer, para lo que te recomendamos leer el Manual de Polymer de DesarrolloWeb.com. Damos por conocidas también diversas herramientas habituales como Bower y Polymer CLI, o el flujo de instalación de componentes, ya que todo esto ha sido objeto de estudio en el mencionado manual.

Creamos nuestro proyecto Polymer

Vamos a comenzar por crear una carpeta para nuestro proyecto y nos introducimos en ella con el terminal.

mkdir polynotifs
cd polynotifs

Ahora vamos a lanzar la inicialización de una aplicación con Polymer CLI. En el asistente seleccionamos: "application: A blank application template". Dicho asistente comienza con el comando:

polymer init

Con esto se crea una sencilla estructura de proyecto, en este caso una aplicación en blanco, que no tiene prácticamente código que nos pueda despistar, aunque sí es interesante porque nos ahorra varios pasos de inicialización.

Instalamos los componentes necesarios para esta demo

A continuación vamos a instalar los componentes que usaremos durante el ejercicio. Algunos ya vienen instalados en la aplicación que se acaba de inicializar, pero para asegurarnos que no nos faltará nada, dejo aquí las sentencias bower para instalarlos.

bower install --save PolymerElements/paper-material
bower install --save PolymerElements/paper-toggle-button
bower install --save PolymerElements/app-layout
bower install --save PolymerElements/platinum-push-messaging

Breve descripción de los componentes que vamos a usar:

  • paper-material: es simplemente un contenedor con una pequeña sombra, estética pura.
  • paper-toggle-button: es un interruptor, encencido/apagado, que usaremos para permitir al usuario que indique si desea o no recibir nuestras notificaciones.
  • app-toolbar: que viene con el paquete de componentes app-layout, que usaremos para nuestras barras de herramientas. Realmente esto lo quiero solo para estética.
  • platinum-push-messaging: este es el componente más importante de este ejemplo, que es el que nos suscribirá a las notificaciones.

Una vez instalados los componentes en el proyecto, no olvides crear los correspondientes import para que tu aplicación los conozca. Te quedará algo como esto:

<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../../bower_components/platinum-push-messaging/platinum-push-messaging.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">

Componente platinum-push-messaging

El componente platinum-push-messaging es bastante sencillo para las cosas que hace, pero hay que conocerlo. Realmente nos ofrece mucha información que necesitaremos para poder realizar todo el ciclo de las notificaciones, como decirnos si las notificaciones están habilitadas para este navegador, cuál es el identificador de la suscripción, etc. Es interesante echarle un vistazo a la documentación del elemento para poder ir familiarizándose con lo que nos ofrece.

El componente lo podemos colocar en cualquier parte de la página y usaremos un único ejemplar para toda la aplicación. Yo lo he colocado en el componente raíz de la aplicación (realmente mi aplicación es tan sencilla que solo tiene un componente mío, el raíz). Su código es el siguiente:

<platinum-push-messaging
      id="notificationElement"
      title="Te ha llegado una notificación"
      message="Este es el mensaje, que debería poder personalizarse"
      enabled="{{notificationsEnabled}}"
></platinum-push-messaging>

Yo aquí no pretendo explicar todas las posibilidades, sino simplemente aquellas que debemos conocer para completar esta demo. Diremos que el identificador me sirve para referirme a él luego desde los métodos de mi componente. Tanto "title" como "message" sirven para definir el contenido de las notificaciones. La propiedad enabled me indica si el componente está preparado para recibir notificaciones push y la tengo bindeada a una propiedad de mi componente que usaremos más tarde.

Para que la magia de platinum-push-messaging sea posible, por debajo se usa un Service Worker. Básicamente es un script que queda residente en el navegador ejecutándose aunque la página esté cerrada. El service Worker puede usarse para muchas cosas y la recepción de notificaciones es una de ellas.

Realmente usando platinum-push-messaging no tenemos que preocuparnos mucho de cómo hacer el service worker, puesto que ya te lo entregan programado al descargarte el componente.

Editar el manifest.json

Es muy importante, para que el componente platinum-push-messaging te funcione, que definas en el archivo manifest.json, que encontrarás en la raíz de tu proyecto, una propiedad con el identificador del emisor de las notificaciones.

"gcm_sender_id": "395279178722"

Luego explicaré de donde obtenemos ese valor del identificador.

El archivo manifest.json quedaría algo como esto:

{
  "name": "polynotifs",
  "short_name": "polynotifs",
  "start_url": "/",
  "display": "standalone",
  "gcm_sender_id": "395279178722"
}

Realmente no he tocado nada de lo que me dieron al inicializar el proyecto, salvo el gcm_sender_id. Tendrás que colocar el tuyo propio, que obtienes desde la consola de Firebase o Google Developer Console, como veremos más tarde.

El interruptor para suscribirnos, o no, a las notificaciones

Por otra parte tengo el interruptor on/off para indicar si queremos o no recibir notificaciones. Lo he colocado dentro de una barra de herramientas con el título de mi página.

<app-toolbar>
      <div main-title>Polynotif</div>
      <paper-toggle-button 
        id="toggle"
        checked="[[notificationsEnabled]]"
      >¿Aceptar Notificaciones?</paper-toggle-button>
</app-toolbar>

Se puede apreciar que el componente paper-toggle-button tiene un identificador, para poder referirnos a él y la propiedad checked, que tenemos bindeada a "notificationsEnabled". Esa propiedad toma valor en el componente platinum-push-messaging, de modo que, si estoy habilitado para recibir notificaciones podré ver que el interruptor está activado, sin programar nada. Y al contrario, si no estamos suscritos a las notificaciones veremos que está en su posición off.

Eventos y manejadores para completar el ciclo de autorización de recepción de notificaciones

Hasta ahora no habíamos programado nada, pero comenzaremos ya. Primero quiero mostrar la declaración de los manejadores de eventos que vamos a usar:

listeners: {
      'toggle.change': 'toggleNotifications',
      'notificationElement.subscription-changed': 'subscriptionChanged'
},

'toggle.change' es el evento que se ejecuta cuando debido a una acción del usuario cambia el estado del interruptor. Al capturarse el evento llamaremos a 'toggleNotifications'.

toggleNotifications: function() {
  if(this.$.toggle.checked) {
    this.$.notificationElement.enable();
  } else {
    this.$.notificationElement.disable();          
  }
},

Aquí gestionamos la suscripción o baja de las notificaciones, dependiendo del estado del interruptor. Lo más interesante es ver cómo el elemento de las notificaciones tiene dos métodos, enable() y disable() que se encargan de realizar el trabajo de suscribir o de-suscribir.

'notificationElement.subscription-changed' se activa cuando hay un cambio en el estado de suscripción a las notificaciones. Cuando se detecte ese evento se invocará el método 'subscriptionChanged'.

subscriptionChanged: function() {
  this.subscriptionId = this.$.notificationElement.subscription ? this.$.notificationElement.subscription.subscriptionId : undefined;
  if (this.$.notificationElement.subscription && !this.$.notificationElement.subscription.subscriptionId) {
    var endpointSections = this.$.notificationElement.subscription.endpoint.split('/');
    this.subscriptionId = endpointSections[endpointSections.length - 1];
  }
}

Este método Puede parecer un poco más complejo, pero solo hace una cosa: obtener el identificador de la suscripción. Ese identificador lo necesitamos para poder mandar mensajes a este usuario.

El identificador de la suscripción se extrae del componente de las notificaciones, con su propiedad subscription. Aunque el componente no te lo entrega tal cual, generalmente está en una cadena con otras cosas, por eso se hace un poco más complejo este código. Observa que prácticamente idéntico al demo oficial de platinum-push-messaging. Lo he sacado de allí.

No lo he mencionado, aunque quien tenga experiencia con Polymer supongo que habrá caído en la cuenta, que lo ideal sería declarar las propiedades que estamos usando, en el objeto de properties.

properties: {
  subscriptionId: {
    type: String
  },
  notificationsEnabled: {
    type: Boolean,
    value: false
  }
},

Mostrar los datos de la suscripción

El resto de código de nuestro componente de la aplicación ya es HTML para mostrar los datos de la suscripción a notificaciones, una vez que se ha detectado habilitada tal suscripción.

<paper-material>
  <div hidden="[[!subscriptionId]]">
    <pre class="paper-font-code1">curl https://android.googleapis.com/gcm/send -d "registration_id=[[subscriptionId]]" --header "Authorization: key=[tu-key]"</pre>
  </div>
  <p>[[subscriptionId]]</p>
</paper-material>

Como salida, que verás cuando se acepten las notificaciones para este sitio web, mostramos un comando de curl, que se compone con los datos de la suscripción y una API- Key del servicio de mensajería. (Esa API Key es secreta, por lo que solo verás en mi código [tu-key]. Luego explicaré para qué quieres ese comando.

Configurar el servicio de mensajería con Firebase

Ahora básicamente tenemos que configurar Google Cloud Messaging (GCM) o Firebase Cloud Messaging (FCM) para obtener dos cosas:

  • El identificador del emisor de notificaciones.
  • La llave de API, privada, que te certifica como dueño de la app desde la que te permiten enviar las notificaciones.

Esta parte la podrías hacer directamente con la Google Developer Console, pero usando Firebase vamos un poco más rápido y evitamos perdernos en medio del proceso para configurar el servicio. Además, FCM ofrece algunas cosas adicionales de las que ofrece GCM, por lo que también se recomienda su uso.

Nota: Este servicio de mensajería de notificaciones es gratuito y en principio no tiene limitaciones. Uno de los motivos por los que solo funciona en Chrome es que estamos usando las notificaciones generadas con su "nube". Me queda la duda de si, cuando se estandarice, podamos usar la nube de Google para enviar notificaciones a todos los navegadores o si cada fabricante tendrá que ofrecer sus propia infraestructura.

El proceso es bien simple.

  1. Vas a la consola de Firebase y creas un nuevo proyecto.
  2. Luego en la rueda dentada del lateral izquierdo, pulsas en "Configuración de proyecto".
  3. Luego pulsas la pestaña "Mensajería en la nube".

Nota: Recuerda que tienes un manual de Firebase para poder resolver tus dudas sobre el uso de este servicio de Google.

Apunta tanto la "Clave del servidor" (API KEY) como el ID de remitente (gcm_sender_id). El id del remitente solo lo necesitas para poder configurar el manifest.json, del que hemos hablado anteriormente en este artículo. La clave del servidor la vamos a usar en breve.

Poner en marcha la aplicación Polymer

Aunque antes que nada, deberíamos probar la aplicación que tenemos desarrollada. Ya sabes, desde el terminal ejecutas "polymer serve --open" y así se pondrá en marcha el servidor web y se abrirá el navegador en la home de tu proyecto.

Deberías de ver algo como esto:

Ahora puedes activar el interruptor y si todo ha ido bien verás debajo la información sobre el id de la suscripción que se genera a través del componente de notificaciones.

Lo más seguro es que el propio Chrome te pida autorización para recibir notificaciones, pero eso depende de cómo tengas configurado el navegador. En opciones avanzadas, de la configuración/ajustes de Chorme, y luego en configuración del contenido podrás marcar cómo quieres que Chrome gestione las notificaciones. Lo recomendado es pedirle a Chorme que se pregunte por la autorización al usuario, para cada sitio que quiera emitir notificaciones, en cuyo caso debe aparecer un mensaje como este:

Ya solo nos queda el último paso, que vamos a ver de una manera simplificada. Se trata de emitir la notificación para que le llegue al navegador del usuario.

Recuerda que no es necesario que el usuario tenga abierta la página de esta aplicación. Si el usuario no tiene abierta la aplicación, solo con que Chrome se esté ejecutando, es suficiente para que la muestre. Eso se consigue gracias al Service Worker que platinum-push-messaging nos ofrece.

Es importante mencionar que para que el service worker funcione la web tiene que ser entregada de manera segura, por https. Sin embargo, el dominio localhost se considera seguro, así que podrás probarlo en local perfectamente, desde http://localhost no desde la IP de tu máquina, aunque no accedas desde un servidor seguro.

Por nuestra parte, para emitir la notificación, lo hacemos desde fuera de la página. Existirían varias maneras, pero lo más típico sería usar programación del lado del backend. En tu servidor tienes que conectar con el API de mensajería de Firebase o Google Cloud y componer y enviar la notificación.

Sin embargo, nosotros lo haremos a modo de demo de una manera más sencilla. Básicamente con un comando de consola. El comando es justamente lo que hay escrito en la caja de color gris de la anterior imagen. Algo como esto:

curl https://android.googleapis.com/gcm/send -d "registration_id=[este_es_el_id_de_suscripcion]" --header "Authorization: key=[esta_es_tu_api_key]"
Nota: Obviamente, necesitas tener funcionando curl en tu máquina, para que ese comando funcione. En la página del demo advierten que esta alternativa de envío de notificaciones es posible en Linux y Mac, pero yo también lo he podido hacer desde Windows. Tanto la web la estoy viendo en Google Chrome para Windows y recibe las notificaciones, como desde el terminal uso curl sin problemas, eso sí, el terminal no es el básico de Windows, sino que estoy usando el "Git Bash", que se instala al instalar Git. Me figuro que teniendo curl instalado funcionará en otros terminales más avanzados como "cmder".

Recuerda que se debería sustituir [este_es_el_id_de_suscripcion] por el identificador de suscripción que obtienes al permitir la recepción de notificaciones (que ves en la web escrito una vez te validas para recibir notificaciones). [esta_es_tu_api_key] la debes de cambiar por la "clave de servidor" que encuentras en la consola de Firebase.

Eso te debe mostrar algo como esto:

Si no te funciona, repasa tu código en vista al repositorio de Github que hemos enlazado al principio de este artículo. Revisa tener el manifest.json bien configurado y que el navegador ha solicitado permiso para recibir notificaciones.

Los permisos de las notificaciones, así como otros detalles de la web se pueden controlar con un click sobre el icono de la izquierda de la URL, en la barra de direcciones del navegador.

Si lo que falla es el service worker, u otra cosa, también podrás recibir mensajes en la consola.

Si lo que falla es el API KEY, deberías recibir un mensaje al ejecutar el comando curl, por consola, en el que verás un error "Unauthorized" con código 401. Otro error que podrías recibir de la consola al ejecutar el comando curl es "Error=MismatchSenderIdmc". En ese caso revisa el manifest y que el "gcm_sender_id" corresponda con la API Key que está usando.

Conclusión

Con esto terminamos nuestra primera introducción a las notificaciones web, que hemos podido implementar de una manera relativamente sencilla, gracias a Firebase y Polymer.

Es cierto que queda bastante trabajo por delante, pero de momento hemos conseguido que las cosas funcionen del lado del cliente y que Chrome nos muestre la "gloriosa" notificación. En futuros artículos veremos otras partes clave para poder dominar el servicio de notificaciones, e implementar las mejoras que seguro estás necesitando, como el envío desde programación backend cuando ocurren eventos en la app y la configuración del cuerpo de las notificaciones.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

Leandro Lera

02/11/2016
notificaciones
ummm y esto funciona en todos los navegadores? móviles también?

midesweb

03/11/2016
Navegadores móviles
Esto son funcionalidades disponibles en Chrome, a día de hoy, pero otros navegadores lo están incorporando. De hecho me suena que Firefox ya lo tiene.
En móviles funciona en Android desde Chrome, pero te digo lo mismo, la tendencia es que sea posible en breve desde otros fabricantes.