Notificaciones push en la Web abierta

Si le preguntas a un grupo de desarrolladores qué funciones de dispositivos móviles faltan en la Web, las notificaciones push siempre están entre las primeras de la lista.

Las notificaciones push permiten a tus usuarios habilitar actualizaciones oportunas de sus sitios preferidos y te permiten volver a atraerlos eficazmente con contenido personalizado y atractivo.

A partir de la versión 42 de Chrome, la API de Push y la API de notificaciones están disponibles para los desarrolladores.

La API de Push en Chrome se basa en distintos tipos de tecnología, como los manifiestos de apps web y los service workers. En esta publicación, analizaremos cada una de estas tecnologías, pero solo lo mínimo para que los mensajes push funcionen. Para comprender mejor algunas de las otras funciones de los manifiestos y las capacidades sin conexión de los service workers, consulta los vínculos anteriores.

También veremos lo que se agregará a la API en versiones futuras de Chrome y, por último, tendremos una sección de Preguntas frecuentes.

Implementación de la mensajería push para Chrome

En esta sección, se describe cada paso que debes completar para admitir la mensajería push en tu app web.

Registra un Service Worker

Existe la dependencia de tener un service worker para implementar mensajes push en la Web. Esto se debe a que, cuando se recibe un mensaje push, el navegador puede iniciar un service worker, que se ejecuta en segundo plano sin que se abra una página, y enviar un evento para que puedas decidir cómo controlar ese mensaje push.

A continuación, se muestra un ejemplo de cómo registrar un service worker en tu app web. Cuando el registro se completa correctamente, llamamos a initialiseState(), que abordaremos en breve.

var isPushEnabled = false;

…

window.addEventListener('load', function() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function() {
    if (isPushEnabled) {
        unsubscribe();
    } else {
        subscribe();
    }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(initialiseState);
    } else {
    console.warn('Service workers aren\'t supported in this browser.');
    }
});

El controlador de clics del botón suscribe o anula la suscripción al usuario para enviar mensajes. isPushEnabled es una variable global que simplemente hace un seguimiento para saber si la mensajería push está suscrita o no. Se hará referencia a ellos en todos los fragmentos de código.

Luego, verificamos que los service workers sean compatibles antes de registrar el archivo service-worker.js que tiene la lógica para manejar un mensaje push. En este caso, simplemente le indicamos al navegador que este archivo JavaScript es el service worker de nuestro sitio.

Configura el estado inicial

Ejemplo de UX de mensajería push habilitada e inhabilitada en Chrome.

Una vez que se registra el service worker, debemos configurar el estado de nuestra IU.

Los usuarios esperarán que una IU sencilla habilite o inhabilite los mensajes push en tu sitio, y que se mantenga actualizada con cualquier cambio que ocurra. En otras palabras, si habilitan los mensajes push para tu sitio, salen y regresan una semana después, tu IU debe destacar que los mensajes push ya están habilitados.

Puedes encontrar algunos lineamientos de UX en este documento. En este artículo, nos enfocaremos en los aspectos técnicos.

En este punto, es posible que pienses que solo hay dos estados con los que tratar: habilitado o inhabilitado. Sin embargo, existen otros estados relacionados con las notificaciones que debes tener en cuenta.

Un diagrama en el que se destacan las diferentes consideraciones y el estado de envío en Chrome

Hay varias APIs que debemos verificar antes de habilitar nuestro botón y, si todo es compatible, podemos habilitar nuestra IU y establecer el estado inicial para indicar si la mensajería push está suscrita o no.

Dado que la mayoría de estas verificaciones hacen que se inhabilite nuestra IU, debes configurar el estado inicial como inhabilitado. Esto también evita cualquier confusión en caso de que haya un problema con el código JavaScript de tu página; por ejemplo, no se puede descargar el archivo JS o el usuario lo inhabilitó.

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

Con este estado inicial, podemos realizar las verificaciones descritas anteriormente en el método initialiseState(), es decir, después de registrar nuestro service worker.

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications aren\'t supported.');
    return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
    console.warn('The user has blocked notifications.');
    return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
    console.warn('Push messaging isn\'t supported.');
    return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
        .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        var pushButton = document.querySelector('.js-push-button');
        pushButton.disabled = false;

        if (!subscription) {
            // We aren't subscribed to push, so set UI
            // to allow the user to enable push
            return;
        }

        // Keep your server in sync with the latest subscriptionId
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
        })
        .catch(function(err) {
        console.warn('Error during getSubscription()', err);
        });
    });
}

Una breve descripción general de estos pasos:

  • Comprobamos que showNotification esté disponible en el prototipo ServiceWorkerRegistration. Sin él, no podremos mostrar una notificación de nuestro service worker cuando se reciba un mensaje push.
  • Verificamos cuál es el Notification.permission actual para asegurarnos de que no sea "denied". Cuando se rechaza un permiso, no puedes mostrar notificaciones hasta que el usuario cambie el permiso de forma manual en el navegador.
  • Para comprobar si se admite la mensajería push, verificamos que PushManager esté disponible en el objeto window.
  • Por último, usamos pushManager.getSubscription() para verificar si ya tenemos una suscripción o no. De ser así, enviamos los detalles de la suscripción a nuestro servidor para asegurarnos de tener la información correcta y configuramos nuestra IU para indicar que la mensajería push ya está habilitada o no. Veremos los detalles que existen en el objeto de suscripción más adelante en este artículo.

Esperamos hasta que se resuelva navigator.serviceWorker.ready para verificar si hay una suscripción y habilitar el botón push, ya que solo puedes suscribirte a los mensajes push después de que el service worker esté activo.

El siguiente paso es controlar cuándo el usuario desea habilitar los mensajes push, pero, antes de hacerlo, debemos configurar un proyecto de Google Developers Console y agregar algunos parámetros a nuestro manifiesto para usar Firebase Cloud Messaging (FCM), antes conocido como Google Cloud Messaging (GCM).

Crea un proyecto en Firebase Developer Console

Chrome usa FCM para manejar el envío y la entrega de mensajes push. Sin embargo, para usar la API de FCM, debes configurar un proyecto en Firebase Developer Console.

Los siguientes pasos son específicos para los navegadores Chrome, Opera para Android y Samsung que usan FCM. Analizaremos más adelante en este artículo cómo funcionaría esto en otros navegadores.

Crea un nuevo proyecto de desarrollador de Firebase

Para comenzar, debes crear un proyecto nuevo en https://console.firebase.google.com/. Para ello, haz clic en “Crear proyecto nuevo”.

Captura de pantalla de un nuevo proyecto de Firebase

Agrega un nombre de proyecto, créalo y se te redireccionará al panel del proyecto:

Página principal del proyecto de Firebase

Desde este panel, haz clic en el engranaje junto al nombre de tu proyecto en la esquina superior izquierda y haz clic en “Configuración del proyecto”.

Menú de configuración del proyecto de Firebase

En la página de configuración, haz clic en la pestaña “Cloud Messaging”.

Menú de Cloud Messaging del proyecto de Firebase

Esta página contiene la clave de API para la mensajería push, que usaremos más adelante, y el ID de remitente que debemos colocar en el manifiesto de la aplicación web en la siguiente sección.

Agrega el manifiesto de una app web

Para el envío, debemos agregar un archivo de manifiesto con un campo gcm_sender_id para que la suscripción de envío se realice correctamente. Este parámetro solo es necesario para los navegadores Chrome, Opera para Android y Samsung para que puedan usar FCM o GCM.

Estos navegadores usan el gcm_sender_id cuando suscribe un dispositivo de un usuario a FCM. Esto significa que FCM puede identificar el dispositivo del usuario y asegurarse de que tu ID de remitente coincida con la clave de API correspondiente y de que el usuario permitió que tu servidor le envíe mensajes push.

A continuación, se muestra un archivo de manifiesto supersimple:

{
    "name": "Push Demo",
    "short_name": "Push Demo",
    "icons": [{
        "src": "images/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
        }],
    "start_url": "/index.html?homescreen=1",
    "display": "standalone",
    "gcm_sender_id": "<Your Sender ID Here>"
}

Deberás establecer el valor gcm_sender_id en el ID de remitente de tu proyecto de Firebase.

Una vez que hayas guardado el archivo de manifiesto en tu proyecto (manifest.json es un buen nombre), haz referencia a él desde tu código HTML con la siguiente etiqueta en el encabezado de la página.

<link rel="manifest" href="/manifest.json">

Si no agregas un manifiesto web con estos parámetros, obtendrás una excepción cuando intentes suscribir al usuario a mensajes push, con el error "Registration failed - no sender id provided" o "Registration failed - permission denied".

Suscribirse a la mensajería de aplicación

Ahora que ya configuraste un manifiesto, puedes volver al código JavaScript de tu sitio.

Para suscribirte, debes llamar al método subscribe() en el objeto PushManager, al que puedes acceder a través de ServiceWorkerRegistration.

Se le pedirá al usuario que otorgue permiso a tu origen para enviar notificaciones push. Sin este permiso, no podrás suscribirte correctamente.

Si se resuelve la promesa que muestra el método subscribe(), se te proporcionará un objeto PushSubscription, que contendrá un extremo.

El extremo debe guardarse en tu servidor para cada usuario, ya que los necesitarás para enviar mensajes push más adelante.

El siguiente código suscribe al usuario a los mensajes push:

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe()
        .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        pushButton.textContent = 'Disable Push Messages';
        pushButton.disabled = false;

        // TODO: Send the subscription.endpoint to your server
        // and save it to send a push message at a later date
        return sendSubscriptionToServer(subscription);
        })
        .catch(function(e) {
        if (Notification.permission === 'denied') {
            // The user denied the notification permission which
            // means we failed to subscribe and the user will need
            // to manually change the notification permission to
            // subscribe to push messages
            console.warn('Permission for Notifications was denied');
            pushButton.disabled = true;
        } else {
            // A problem occurred with the subscription; common reasons
            // include network errors, and lacking gcm_sender_id and/or
            // gcm_user_visible_only in the manifest.
            console.error('Unable to subscribe to push.', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        }
        });
    });
}

En este punto, tu app web está lista para recibir un mensaje push, aunque no pasará nada hasta que agreguemos un objeto de escucha de eventos push a nuestro archivo de service worker.

Objeto de escucha de eventos push de service worker

Cuando se reciba un mensaje push (hablaremos sobre cómo enviar un mensaje push en la siguiente sección), se enviará un evento push a tu service worker. En ese momento, deberás mostrar una notificación.

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

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

Este código registra un objeto de escucha de eventos push y muestra una notificación con un título, texto del cuerpo, ícono y una etiqueta de notificación predefinidos. Una sutileza que debes destacar en este ejemplo es el método event.waitUntil(). Este método recibe una promesa y extiende la vida útil de un controlador de eventos (o puede considerarse que mantiene activo el service worker) hasta que la promesa se establece. En este caso, la promesa que se pasa a event.waitUntil es la promesa que se muestra de showNotification().

La etiqueta de notificación actúa como un identificador para notificaciones únicas. Si enviamos dos mensajes push al mismo extremo, con una breve demora entre ellos, y mostramos notificaciones con la misma etiqueta, el navegador mostrará la primera notificación y la reemplazará con la segunda cuando se reciba el mensaje push.

Si deseas mostrar varias notificaciones a la vez, utiliza una etiqueta diferente o no utiliza ninguna etiqueta. Veremos un ejemplo más completo de cómo mostrar una notificación más adelante en esta publicación. Por ahora, mantengamos las cosas simples y veamos si el envío de un mensaje push muestra esta notificación.

Envía un mensaje push

Nos suscribimos a los mensajes push y nuestro service worker está listo para mostrar una notificación. Es hora de enviar un mensaje push a través de FCM.

Esto solo se aplica a los navegadores que usan FCM.

Cuando envías la variable PushSubscription.endpoint a tu servidor, el extremo de FCM es especial. Tiene un parámetro al final de la URL, que es un registration_id.

Un extremo de ejemplo sería el siguiente:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

La URL de FCM es la siguiente:

https://fcm.googleapis.com/fcm/send

La registration_id sería la siguiente:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

Esto es específico para los navegadores que usan FCM. En un navegador normal, solo obtendrías un extremo, lo llamarías de manera estándar y funcionaría independientemente de la URL.

Esto significa que, en tu servidor, deberás verificar si el extremo es para FCM y, de ser así, extraer el register_id. Para hacer esto en Python, puedes hacer lo siguiente:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

Una vez que tengas el ID de registro, podrás realizar una llamada a la API de FCM. Encontrarás documentos de referencia sobre la API de FCM aquí.

Estos son los aspectos clave que debes recordar cuando llames a FCM:

  • Se debe configurar un encabezado de Authorization con un valor de key=&lt;YOUR_API_KEY&gt; cuando llamas a la API, en el que &lt;YOUR_API_KEY&gt; es la clave de API del proyecto de Firebase.
    • FCM usa la clave de API para encontrar el ID de remitente adecuado, asegúrate de que el usuario haya otorgado permiso para tu proyecto y, finalmente, asegurarte de que la dirección IP del servidor esté incluida en la lista de entidades permitidas de ese proyecto.
  • Un encabezado Content-Type adecuado de application/json o application/x-www-form-urlencoded;charset=UTF-8, según si envías los datos en formato JSON o como datos de formulario
  • Un array de registration_ids: estos son los ID de registro que debes extraer de los extremos de tus usuarios.

Consulta los documentos sobre cómo enviar mensajes push desde tu servidor, pero si quieres realizar una verificación rápida de tu service worker, puedes usar cURL para enviar un mensaje push a tu navegador.

Intercambia &lt;YOUR_API_KEY&gt; y &lt;YOUR_REGISTRATION_ID&gt; en este comando cURL por el tuyo y ejecútalo desde una terminal.

Deberías ver una notificación excelente:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Ejemplo de un mensaje push de Chrome para Android.

Cuando desarrolles tu lógica de backend, recuerda que el encabezado y el formato del cuerpo de POST son específicos del extremo de FCM, por lo que debes detectar cuándo el extremo es para FCM y agregar de forma condicional el encabezado y darle formato al cuerpo de POST. Para otros navegadores (y Chrome en el futuro), deberás implementar el protocolo de notificaciones push web.

Una desventaja de la implementación actual de la API de Push en Chrome es que no puedes enviar datos con un mensaje push. No, nada. Esto se debe a que, en una implementación futura, los datos de la carga útil deberán encriptarse en tu servidor antes de enviarlos a un extremo de mensajería push. De esta manera, el extremo, sin importar el proveedor de envío que sea, no podrá ver con facilidad el contenido del mensaje de envío. Esto también brinda protección contra otras vulnerabilidades, como una validación deficiente de los certificados HTTPS y los ataques de intermediario entre tu servidor y el proveedor de envío. Sin embargo, esta encriptación aún no se admite, por lo que, mientras tanto, deberás realizar una recuperación a fin de obtener la información necesaria para propagar una notificación.

Un ejemplo más completo de evento push

La notificación que vimos hasta ahora es bastante básica y, en lo que respecta a las muestras, no es bastante buena para cubrir un caso de uso del mundo real.

En realidad, la mayoría de las personas querrán obtener cierta información de su servidor antes de mostrar la notificación. Estos pueden ser datos para propagar el título y el mensaje de la notificación con algo específico, o ir un paso más allá y almacenar en caché algunas páginas o datos para que, cuando el usuario haga clic en la notificación, todo esté disponible de inmediato cuando se abra el navegador, incluso si la red no está disponible en ese momento.

En el siguiente código, recuperamos algunos datos de una API, convertimos la respuesta en un objeto y la usamos para propagar la notificación.

self.addEventListener('push', function(event) {
    // Since there is no payload data with the first version
    // of push messages, we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(SOME_API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        // Either show a message to the user explaining the error
        // or enter a generic message and handle the
        // onnotificationclick event to direct the user to a web page
        console.log('Looks like there was a problem. Status Code: ' + response.status);
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        if (data.error || !data.notification) {
            console.error('The API returned an error.', data.error);
            throw new Error();
        }

        var title = data.notification.title;
        var message = data.notification.message;
        var icon = data.notification.icon;
        var notificationTag = data.notification.tag;

        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this push message';
        var icon = URL_TO_DEFAULT_ICON;
        var notificationTag = 'notification-error';
        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
    })
    );
});

Una vez más, vale la pena destacar que event.waitUntil() toma una promesa que da como resultado la promesa que muestra showNotification(), lo que significa que nuestro objeto de escucha de eventos no se cerrará hasta que se complete la llamada a fetch() asíncrona y se muestre la notificación.

Notarás que mostramos una notificación incluso cuando hay un error. Esto se debe a que, si no lo hacemos, Chrome mostrará su propia notificación genérica.

Abrir una URL cuando el usuario hace clic en una notificación

Cuando el usuario hace clic en una notificación, se envía un evento notificationclick a tu service worker. En el controlador, puedes tomar las medidas correspondientes, como enfocar una pestaña o abrir una ventana con una URL en particular:

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn't close the notification when you click on it
    // See: http://crbug.com/463146
    event.notification.close();

    // This looks to see if the current is already open and
    // focuses if it is
    event.waitUntil(
    clients.matchAll({
        type: "window"
    })
    .then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
            return client.focus();
        }
        if (clients.openWindow) {
        return clients.openWindow('/');
        }
    })
    );
});

En este ejemplo, se abre el navegador en la raíz del origen del sitio. Para ello, se enfoca una pestaña del mismo origen (si la hay) y se abre una nueva.

Hay una publicación dedicada a algunas de las acciones que puedes hacer con la API de Notification aquí.

Anula la suscripción al dispositivo de un usuario

Si te suscribiste al dispositivo de un usuario y este recibe mensajes push, ¿cómo puedes anular la suscripción?

Lo principal necesario para anular la suscripción del dispositivo de un usuario es llamar al método unsubscribe() en el objeto PushSubscription y quitar el extremo de tus servidores (solo para no enviar mensajes push que sabes que no se recibirán). El siguiente código hace exactamente esto:

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subscription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
        function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
            // No subscription object, so set the state
            // to allow the user to subscribe to push
            isPushEnabled = false;
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            return;
        }

        var subscriptionId = pushSubscription.subscriptionId;
        // TODO: Make a request to your server to remove
        // the subscriptionId from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subscription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            isPushEnabled = false;
        }).catch(function(e) {
            // We failed to unsubscribe, this can lead to
            // an unusual state, so may be best to remove
            // the users data from your data store and
            // inform the user that you have done so

            console.log('Unsubscription error: ', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        });
        }).catch(function(e) {
        console.error('Error thrown while unsubscribing from push messaging.', e);
        });
    });
}

Cómo mantener la suscripción actualizada

Es posible que las suscripciones entre FCM y tu servidor no estén sincronizadas. Asegúrate de que tu servidor analice el cuerpo de la respuesta de la solicitud POST de envío de la API de FCM y busque resultados de error:NotRegistered y canonical_id, como se explica en la documentación de FCM.

También es posible que las suscripciones no estén sincronizadas entre el service worker y tu servidor. Por ejemplo, después de suscribirte o anular la suscripción correctamente, es posible que una conexión de red inestable te impida actualizar tu servidor o que un usuario revoque el permiso de notificaciones, lo que activa una anulación de la suscripción automática. Para controlar estos casos, verifica el resultado de serviceWorkerRegistration.pushManager.getSubscription() de forma periódica (p.ej., cuando se carga la página) y sincronízalo con el servidor. Es posible que también quieras volver a suscribirte automáticamente si ya no tienes una suscripción y Notification.permission == 'granted'.

En sendSubscriptionToServer(), deberás considerar cómo manejas las solicitudes de red fallidas cuando actualizas endpoint. Una solución es realizar un seguimiento del estado de endpoint en una cookie para determinar si tu servidor necesita los detalles más recientes o no.

Todos los pasos anteriores dan como resultado una implementación completa de la mensajería push en la Web en Chrome 46. Aún existen funciones especificadas que facilitarán el proceso (como una API estándar para activar mensajes push), pero esta versión te permite comenzar a crear mensajes push en tus apps web hoy mismo.

Cómo depurar tu app web

Durante la implementación de los mensajes push, los errores se encontrarán en uno de estos dos lugares: tu página o tu service worker.

Los errores en la página se pueden depurar con DevTools. Para depurar los problemas relacionados con los service workers, tienes dos opciones:

  1. Ve a chrome://inspect > Service workers. Esta vista no proporciona mucha información además de los service workers que se ejecutan actualmente.
  2. Ve a chrome://serviceworker-internals y, desde aquí, puedes ver el estado de los service workers y los errores, si los hay. Esta página será temporal hasta que Herramientas para desarrolladores tenga un conjunto de funciones similar.

Una de las mejores sugerencias que puedo darle a cualquier persona que no tenga experiencia en los service workers es usar la casilla de verificación denominada "Abrir la ventana de Herramientas para desarrolladores y pausar la ejecución de JavaScript al inicio del service worker para depurar". Esta casilla de verificación agregará un punto de interrupción al inicio de tu service worker y pausará la ejecución. Esto te permitirá reanudar o revisar la secuencia de comandos del service worker y ver si se produjo algún problema.

Captura de pantalla en la que se muestra dónde se encuentra la casilla de verificación para pausar la ejecución en serviceworker-internals.

Si parece que hay un problema entre FCM y el evento push de tu service worker, no puedes hacer mucho para depurarlo, ya que no hay forma de ver si Chrome recibió algo. El aspecto clave que debes asegurarte de que la respuesta de FCM sea exitosa cuando tu servidor realice una llamada a la API. Se verá algo así:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

Observa la respuesta "success": 1. Si, en cambio, ves un error, significa que hay un problema con el ID de registro de FCM y que el mensaje push no se envía a Chrome.

Depuración de Service Workers en Chrome para Android

Por el momento, la depuración de service workers en Chrome para Android no es evidente. Debes navegar a chrome://inspect, encontrar tu dispositivo y buscar un elemento de lista con el nombre "Worker pid:...." que tenga la URL de tu service worker.

Captura de pantalla que muestra dónde se inspeccionan los service workers en Chrome

UX para notificaciones de aplicación

El equipo de Chrome creó un documento de prácticas recomendadas para la UX de notificaciones push, así como un documento que abarca algunos de los casos extremos cuando se trabaja con notificaciones push.

El futuro de la mensajería push en Chrome y la Web abierta

En esta sección, se detallan algunas de las partes específicas de Chrome de esta implementación que debes tener en cuenta y cómo diferirá de otras implementaciones del navegador.

Protocolo de envío web y extremos

Lo bueno del estándar de la API de Push es que debes poder tomar el extremo, pasarlo a tu servidor y enviar mensajes push mediante la implementación del protocolo de envío web.

El protocolo de envío web es un nuevo estándar que los proveedores de envío pueden implementar, lo que permite a los desarrolladores no tener que preocuparse por quién es el proveedor de envío. La idea es que esto evita la necesidad de registrarse para obtener claves de API y enviar datos con formato especial, como lo haces con FCM.

Chrome fue el primer navegador en implementar la API de Push y FCM no es compatible con el protocolo de envío web. Por este motivo, Chrome requiere la gcm_sender_id y debes usar la API de RESTful para FCM.

El objetivo final para Chrome es avanzar hacia el uso del protocolo de envío web con Chrome y FCM.

Hasta entonces, debes detectar el extremo “https://fcm.googleapis.com/fcm/send” y manejarlo por separado de otros extremos, es decir, formatear los datos de carga útil de una manera específica y agregar la clave de autorización.

¿Cómo implementar el protocolo de envío web?

En este momento, Firefox Nightly está trabajando en el envío y es probable que sea el primer navegador en implementar el protocolo de envío web.

Preguntas frecuentes

¿Dónde están las especificaciones?

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

¿Puedo evitar notificaciones duplicadas si mi presencia en la Web tiene varios orígenes o si tengo presencia nativa y en la Web?

No hay una solución para esto en este momento, pero puedes seguir el progreso en Chromium.

La situación ideal sería tener algún tipo de ID para el dispositivo de un usuario y, luego, en el servidor, hacer coincidir los ID de suscripción de la app nativa y la app web y decidir a cuál enviar un mensaje push. Podrías hacerlo a través del tamaño de la pantalla, el modelo del dispositivo y compartiendo una clave generada entre la app web y la app nativa, pero cada enfoque tiene ventajas y desventajas.

¿Por qué necesito un gcm_sender_id?

Esto es necesario para que Chrome, Opera para Android y el navegador de Samsung puedan usar la API de Firebase Cloud Messaging (FCM). El objetivo es usar el protocolo de envío web cuando se finaliza el estándar y FCM puede admitirlo.

¿Por qué no usar Web Sockets o eventos enviados por el servidor (EventSource)?

La ventaja de usar mensajes push es que, incluso si la página está cerrada, tu service worker se despertará y podrá mostrar una notificación. Web Sockets y EventSource tienen su conexión cerrada cuando se cierra la página o el navegador.

¿Qué sucede si no necesito enviar eventos en segundo plano?

Si no necesitas entrega en segundo plano, entonces Web Sockets es una excelente opción.

¿Cuándo puedo usar notificaciones push sin mostrar notificaciones (es decir, push silenciosa en segundo plano)?

No hay un cronograma para saber cuándo estará disponible, pero hay un intent para implementar la sincronización en segundo plano y, si bien no está decidido ni especificado, hay algunos temas sobre la habilitación del envío silencioso con la sincronización en segundo plano.

¿Por qué esto requiere HTTPS? ¿Cómo corrijo esto durante el desarrollo?

Los service workers requieren orígenes seguros para garantizar que la secuencia de comandos del service worker sea del origen previsto y no provenga de un ataque de intermediarios. En la actualidad, eso significa que debes usar HTTPS en sitios activos, aunque localhost funcionará durante el desarrollo.

¿Cómo funciona la compatibilidad con los navegadores?

Chrome admite la versión estable, y Mozilla está trabajando en la implementación de push en Firefox Nightly. Consulta el error sobre cómo implementar la API de Push para obtener más información y puedes hacer un seguimiento de su implementación de notificaciones aquí.

¿Puedo quitar una notificación después de un período determinado?

Por el momento, esto no es posible, pero planeamos agregar compatibilidad para obtener una lista de las notificaciones visibles. Si tienes un caso de uso en el que se define un vencimiento para las notificaciones después de que se muestra su creación, nos encantaría saber de qué se trata. Por lo tanto, agrega un comentario y se lo enviaremos al equipo de Chrome.

Si solo necesitas evitar que se envíe una notificación push al usuario después de un período determinado y no te importa cuánto tiempo permanezca visible la notificación, puedes usar el parámetro de tiempo de actividad (ttl) de FCM, obtén más información aquí.

¿Cuáles son las limitaciones de la mensajería push en Chrome?

Existen algunas limitaciones que se describen en esta publicación:

  • El uso de Chrome de la CCM como servicio push crea una serie de requisitos de propiedad. Estamos trabajando juntos para ver si algunos de estos se pueden mejorar en el futuro.
  • Debes mostrar una notificación cuando recibes un mensaje push.
  • Chrome para computadoras de escritorio tiene la salvedad de que, si no se ejecuta, no se recibirán los mensajes push. Esto es diferente de ChromeOS y Android, en los que siempre se recibirán mensajes push.

¿No deberíamos usar la API de Permissions?

La API de Permission se implementa en Chrome, pero no necesariamente estará disponible en todos los navegadores. Aquí puedes obtener más información.

¿Por qué Chrome no abre la pestaña anterior cuando hago clic en una notificación?

Este problema solo afecta a las páginas que actualmente no controla un service worker. Aquí puedes obtener más información sobre el tema.

¿Qué sucede si una notificación está desactualizada para el momento en que el dispositivo del usuario recibió el envío?

Siempre debes mostrar una notificación cuando recibes un mensaje push. Si deseas enviar una notificación, pero solo es útil durante un período determinado, puedes usar el parámetro “time_to_live” en la CCM para que FCM no envíe el mensaje push si se supera la hora de vencimiento.

Puedes obtener más detalles aquí.

¿Qué sucede si envío 10 mensajes push, pero solo quiero que el dispositivo reciba uno?

FCM tiene un parámetro "contraer_key" que se puede usar para indicarle a FCM que reemplace cualquier mensaje pendiente que tenga el mismo "contraer_key" por el mensaje nuevo.

Puedes obtener más detalles aquí.