Sigue empujando, con el API W3C Push

19 marzo, 2016 3:30 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks. Traducción por Patricia Argüello.

Todos están familiarizados con esta experiencia — un pequeña burbuja en tu teléfono sin previo aviso, conteniendo un persistente mensaje a lo largo de las líneas “tus insípidamente adorables monstruitos están descansados, y quieren ir a pelear más batallas!”, o “Tienes peticiones de amistad sin responder de gente que no conoces. Date prisa y contesta!

Los mensajes push o notificaciones automáticas , definitivamente no son un nuevo concepto, habiendo sido una característica popular de las plataformas móviles durante años. No obstante, es apenas reciente la llegada de Push a la plataforma web. Este artículo te llevará a través de los aspectos básicos, y líneas generales del actual estado de Push.

La ventaja de Push sobre otra elección de tecnologías para el envío de mensajes a los usuarios es que los mensajes push permiten al usuario suscribirse a actualizaciones sin intervención en absoluto del cliente — mientras el servidor tenga el endpoint (véase abajo), puede enviar actualizaciones a los clientes suscritos sólo cuando lo requieran (por ejemplo, no requieren una conexión constante como los sockets, lo cual es bueno para la duración de la batería, etc.)

Nota: MDN incluye una documentación de referencia completa para el API Push así como un tutorial detallado, Usando el API Push.

Navegadores compatibles

El Push API se encuentra actualmente en fase de proyecto (El último borrador del editor está aquí)

La mayoría del API tiene soporte en versiones lanzadas recientemente de Chrome (42+), y Firefox (42+) en canales de pre-lanzamiento por ahora (Nightly, Developer Edition, y Beta). La excepción es PushMessageData, la cual es actualmente soportada solo en Firefox 44+ (igualmente en los canales pre-lanzamiento).

Push requiere service workers para ejecutarse, los cuales son también soportados en su mayoría en las últimas versiones de Chrome y Firefox. Dado que los service workers requieren https para trabajar por razones de seguridad, Push también requiere https.

Merece la pena señalar que Push es a menudo usado junto con APIs de comunicación como Notificaciones Web y Canales de Mensajes para comunicar los resultados de Push que son enviados. Ambos tienen un soporte bastante amplio entre los navegadores modernos.

El proceso de push

En esta sección examinaremos un proceso típico por el cual una app se puede construir utilizando mensajes push.

Nota: puedes encontrar una demo mostrando el uso del API Push en Github. Te será de utilidad conseguir ejecutarla de tal manera que puedas seguirla junto con la lectura de las secciones siguientes.

Solicitar permisos

La primera cosa que deberías hacer es solicitar permiso para notificaciones web, o cualquier otra cosa que estés utilizando que requiere permisos. Por ejemplo:

Notification.requestPermission();

Registrar un service worker y subscribirse a push

La próxima cosa es registrar un service worker para controlar la página, usando ServiceWorkerContainer.register(). Esto retorna una promesa (objeto promise de JavaScript)  que se resuelve con el objeto ServiceWorkerRegistration:

navigator.serviceWorker.register('sw.js').then(function(reg) {
  // hacer algo con el objeto reg
});

Una vez que tenemos este objeto de inscripción, podemos comenzar a registrarnos para Push. A menudo enviarás el objeto ServiceWorkerRegistration para alguna clase de función de subscripción.

En cualquier momento podremos chequear que el service worker está activo y listo para comenzar a hacer cosas usando la propiedad ServiceWorkerContainer.ready, la cual retorna una promesa que se resuelve con el citado objeto ServiceWorkerRegistration. Una vez que tenemos esto, podemos acceder a PushManager usando la propiedad ServiceWorkerRegistration.pushManager. Entonces podemos subscribirnos a el servicio Push usando PushManager.subscribe(), el cual retorna una promesa que se resuelve con PushSubscription object.

navigator.serviceWorker.ready.then(function(reg) {
  reg.pushManager.getSubscription()
  .then(function(subscription) {
    // hacer algo con el objeto PushSubscription
  });
}

Para darse de baja, el código es similar, pero deberás usar el método PushSubscription.unsubscribe():

navigator.serviceWorker.ready.then(function(reg) {
  reg.pushManager.getSubscription()
  .then(function(subscription) {
    subscription.unsubscribe().then(function(successful) {
      // dado de baja correctamente
    })
  });
}

Servidores push, y envío de mensajes push

Para enviar push messages, necesitas un componente de servidor. Esto puede ser escrito con cualquier lenguaje del lado del servidor que te guste, mientras pueda manejar solicitudes y respuestas, y asegurar encriptado de datos. (Los mensajes Push requieren https, y los datos enviados por push necesitan estar encriptados).

Nota: El soporte de PushMessageData y encryption existe actualmente sólo en Firefox, con el proceso de encriptado todavía siendo desarrollado. (Encriptado y getKey() todavía no aparecen en la especificación).

Una vez que tenemos nuestro objeto PushSubscription, necesitamos hacernos con dos piezas de información que son usadas para el envío de mensajes push:

  • PushSubscription.endpoint: Esto es una única URL apuntando al servidor push que maneja el envío de mensajes push (cada navegador tendrá su propio servidor push). Por ejemplo: https://updates.push.services.mozilla.com/push/gAAAAABWJ-VZaQ9DhwvjZJHEHlZCzNJBPTPAcucU9mprtyzisSow75qHbY5lrjglEXE7G6SIfWvz-QSwhBcjpRjx2PAnKCAHd-5XHh1RFXa1ngqq_2-I0-PZoEqigI7E3ISO5zE1tNy29_Iyiu06m0tc_2nfKyuEcjwDPLyOC8c3IvawhBUUzMM=. Esto es usado por tu servidor para el envío de mensaje push – la petición llega al servidor push, y la cadena aleatoria del final asegura que el mensaje push es enviado al service worker asociado con esa particular suscripción.
  • PushSubscription.getKey(‘p256dh’): Este método genera una llave cliente pública, uno de los componentes usados para encriptar los datos. Estos detalles deberían entonces ser enviados al servidor de tal manera que pueda enviar mensajes push cuando sean requeridos. (Puedes usar Fetch o XMLHttpRequest para hacerlo.)

En el lado servidor, deberías almacenar el endpoint y cualquier otro detalle requerido de tal manera que estén disponibles cuando un mensaje push necesite ser enviado a un subscriptor push (usando una base de datos o lo que quieras). En una aplicación en producción, hay que asegurarse que estos detalles quedan ocultos, para que terceros con malas intenciones no puedan robar los endpoints y enviar spam a los suscriptores con mensajes push. Cualquiera con el endpoint puede enviar un mensaje push, mientras la suscripción permanezca activa.

Para enviar un mensaje push sin datos necesitas enviarlo a la dirección URL del endpoint con un método POST. Para enviar datos en Firefox, necesitas encriptarlos, lo cual requiere una clave cliente pública. Esto es un procedimiento bastante complejo (lee Message Encryption for Web Push para más detalles). A medida que el tiempo avance, las librerías serán escritas para hacer esta clase de cosas por ti; la web-push library en NodeJS por Marco Castelluccio es una buena opción actualmente para NodeJS.

El service worker, y la respuesta a los mensajes push

En tu service worker, necesitas configurar un manejador onpush para responder a los mensajes push que sean recibidos.

self.addEventListener('push', function(event) {
  var obj = event.data.json();
  // hacer algo con el JSON
});

Date cuenta de que el objeto evento es del tipo PushEvent; las propiedades de sus datos contienen un objeto PushMessageData, el cual contiene los datos enviados al mensaje push. Este objeto tiene métodos disponibles para devolver el mensaje payload como un blob, array buffer, objeto JSON, o cadenas de texto planas (estamos convirtiéndolas a JSON arriba). Una vez que tienes el contenido, puedes hacer lo que quieras con él.

Envío por canal de mensajes

Si quieres responder al evento push mediante un canal de mensajes de vuelta al contexto principal, primero necesitas abrir un canal de mensaje entre el contexto principal y el service worker. En el contexto principal, puedes hacer algo como lo esto:

navigator.serviceWorker.ready.then(function(reg) {
  var channel = new MessageChannel();
  channel.port1.onmessage = function(e) {
    handleChannelMessage(e.data);
  }

  mySW = reg.active;
  mySW.postMessage('hello', [channel.port2]);
});

Primero creamos un nuevo objeto MessageChannel usando un constructor, después configuramos un manejador onmessage para gestionar los mensajes que vienen a través del canal al contexto principal.

Entonces, como antes, tenemos una referencia a nuestro objeto ServiceWorkerRegistration. Podemos usar su propiedad active para devolver un objeto ServiceWorker. Podemos usar el método postMessage() del objeto ServiceWorker para enviar un mensaje al contexto al contexto del service worker, por el puerto port2 del canal de mensaje.

En el service worker, tomamos referencia al puerto port2 usando lo siguiente:

var port;

self.onmessage = function(e) {
  port = e.ports[0];
}

Una vez que el enlace se ha establecido, los datos pueden ser enviados de vuelta al contexto principal usando:

port.postMessage('mi mensaje');

Disparando una notificación

Si quieres responder mediante el envío de una notificación de sistema, puedes hacer esto usando ServiceWorkerRegistration.showNotification:

function fireNotification(obj, event) {
  var title = 'Subscription change';
  var body = obj.name + ' has ' + obj.action + 'd.';
  var icon = 'push-icon.png';
  var tag = 'push';

  event.waitUntil(self.registration.showNotification(title, {
    body: body,
    icon: icon,
    tag: tag
  }));
}

Date cuenta  que aquí hemos ejecutado esto dentro de un método ExtendableEvent.waitUntil — éste extiende la duración del evento hasta después de que la notificación se haya lanzado, así que podemos estar seguros de que todo ha ocurrido como pretendíamos.

Manejar el expirado prematuro de suscripciones

A veces las suscripciones push expiran prematuramente, sin que se llame al método unsubscribe(). Esto puede ocurrir cuando el servidor está saturado, o si estás desconectado demasiado tiempo. Esto tiene una alta dependencia del servidor, así que el comportamiento exacto es difícil de predecir. En cualquier caso, puedes manejar este problema usando  el manejador onsubscriptionchange, el cual será invocado solo en este caso específico.

self.addEventListener('subscriptionchange', function() {
  // hacer algo, usualmente reinscribirse en a push y
  // y enviar los nuevos detalles de inscripción de vuelta
  // al servidor con XHR o Fetch
});

La compatibilidad en Chrome para Push

Chrome tiene un buen soporte para Push también, pero cuenta con algunas diferencias respecto a Firefox. Para empezar, todavía no soporta el envío PushMessageData  en mensajes Push; también se basa en el servicio Google Cloud Messaging. Lee pasos extra para el soporte en Chrome para conocer todos los detalles.

The following two tabs change content below.

jorgev

AMO Product Manager at Mozilla
Jorge trabaja para el equipo de complementos de Mozilla, y se dedica a Mozilla Hispano y Mozilla Costa Rica en su tiempo libre. Actualmente está encargado del blog de Mozilla Hispano Labs.

Compartir artículo:

Empezar la discusión en foro.mozilla-hispano.org

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa