Notificaciones push en la Web abierta

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

Las notificaciones push permiten a los usuarios acceder a actualizaciones oportunas desde 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 Notifications están disponibles para los desarrolladores.

La API de Push en Chrome se basa en algunas tecnologías diferentes, incluidos 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 estén en funcionamiento. Para comprender mejor algunas de las otras funciones de los manifiestos y las capacidades sin conexión de los trabajadores de servicio, 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.

Implementa la mensajería push para Chrome

En esta sección, se describe cada paso que debes completar para admitir los mensajes push en tu app web.

Registra un service worker

Se necesita un trabajador de servicio para implementar mensajes de aplicación para la Web. El motivo es que, cuando se recibe un mensaje push, el navegador puede iniciar un servicio de trabajo, que se ejecuta en segundo plano sin que esté abierta 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 trabajador de servicio en tu app web. Cuando el registro se haya completado correctamente, llamaremos a initialiseState(), que analizaremos 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 cancela la suscripción del usuario a los mensajes push. isPushEnabled es una variable global que simplemente realiza un seguimiento de si el usuario está suscrito o no a los mensajes push. 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. Aquí, solo le indicamos al navegador que este archivo JavaScript es el service worker de nuestro sitio.

Configura el estado inicial

Ejemplo de UX de la mensajería push habilitada y no habilitada en Chrome.

Una vez que se registre el trabajador de servicio, debemos configurar el estado de nuestra IU.

Los usuarios esperan una IU simple para habilitar o inhabilitar los mensajes push de tu sitio, y esperan que se mantenga actualizada con los cambios que se produzcan. En otras palabras, si habilitan los mensajes push para tu sitio, sal y vuelve una semana después. Tu IU debería 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, hay algunos 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 una serie de 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 inhabilitan nuestra IU, debes establecer 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, si no se puede descargar el archivo JS o si el usuario inhabilitó JavaScript.

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

Con este estado inicial, podemos realizar las verificaciones que se describieron anteriormente en el método initialiseState(), es decir, después de que se registre 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:

  • Verificamos que showNotification esté disponible en el prototipo de ServiceWorkerRegistration. Sin ella, 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". Si se rechaza un permiso, no podrás 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. Si lo hacemos, enviamos los detalles de la suscripción a nuestro servidor para asegurarnos de tener la información correcta y configuramos nuestra IU para indicar si los mensajes push ya están habilitados o no. Más adelante en este artículo, veremos qué detalles existen en el objeto de suscripción.

Esperamos a 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 trabajador de servicio esté activo.

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

Crea un proyecto en la consola de desarrolladores de Firebase

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

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

Crea un proyecto de desarrollador de Firebase nuevo

Para comenzar, debes crear un proyecto nuevo en https://console.firebase.google.com/ haciendo clic en "Create New Project".

Captura de pantalla de un nuevo proyecto de Firebase

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

Página principal del proyecto de Firebase

En este panel, haz clic en el engranaje junto al nombre de tu proyecto en la esquina superior izquierda y, luego, 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 Firebase Cloud Messaging del proyecto

Esta página contiene la clave de API para los mensajes push, que usaremos más adelante, y el ID del remitente que debemos colocar en el manifiesto de la app web en la siguiente sección.

Agrega el manifiesto de una app web

Para las notificaciones push, debemos agregar un archivo de manifiesto con un campo gcm_sender_id para que la suscripción a notificaciones push 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 gcm_sender_id cuando suscriben el dispositivo de un usuario con FCM. Esto significa que FCM puede identificar el dispositivo del usuario y asegurarse de que el ID de emisor coincida con la clave de API correspondiente y de que el usuario haya permitido que tu servidor le envíe mensajes push.

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

{
    "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 de gcm_sender_id en el ID de emisor 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 la parte superior de la página.

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

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

Cómo suscribirse a la Mensajería push

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

Para suscribirte, debes llamar al método subscribe() en el objeto PushManager, al que accedes 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 se debe guardar en tu servidor para cada usuario, ya que lo 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 sucederá 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 recibe un mensaje push (hablaremos sobre cómo enviar un mensaje push en la siguiente sección), se enviará un evento push en tu service worker, momento en el que 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, un texto del cuerpo, un í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 toma una promesa y extiende la vida útil de un controlador de eventos (o se puede considerar como mantener el service worker activo) hasta que la promesa se liquida. En este caso, la promesa que se pasa a event.waitUntil es la promesa que se muestra desde 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, usa una etiqueta diferente o no uses ninguna. Más adelante en esta publicación, veremos un ejemplo más completo de cómo mostrar una notificación. Por ahora, mantengamos la simplicidad y veamos si se muestra esta notificación cuando se envía un mensaje push.

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 ejemplo de extremo 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

El registration_id sería el siguiente:

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

Esto es específico de los navegadores que usan FCM. En un navegador normal, solo obtendrías un extremo y lo llamarías de una 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 registration_id. Para hacerlo 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, puedes realizar una llamada a la API de FCM. Puedes encontrar documentos de referencia sobre la API de FCM aquí.

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

  • Se debe configurar un encabezado Authorization con un valor de key=&lt;YOUR_API_KEY&gt; cuando llames 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, asegurarse de que el usuario haya otorgado permiso para tu proyecto y, por último, garantizar que la dirección IP del servidor esté incluida en la lista de entidades permitidas para 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.

Cambia &lt;YOUR_API_KEY&gt; y &lt;YOUR_REGISTRATION_ID&gt; en este comando cURL por los tuyos 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 de autorización 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, sea cual sea el proveedor de notificaciones push, no podrá ver fácilmente el contenido del mensaje push. Esto también protege contra otras vulnerabilidades, como una validación deficiente de los certificados HTTPS y ataques de intermediarios entre tu servidor y el proveedor de notificaciones push. Sin embargo, esta encriptación aún no es compatible, por lo que, mientras tanto, deberás realizar una recuperación para 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 los ejemplos, es bastante pobre en la cobertura de un caso de uso del mundo real.

En realidad, la mayoría de las personas querrán obtener 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 bien 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 nuestra 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
        });
    })
    );
});

Vale la pena, una vez más, destacar que event.waitUntil() toma una promesa, lo que genera la promesa que muestra showNotification(), lo que significa que nuestro objeto de escucha de eventos no se cerrará hasta que se complete la llamada asíncrona a fetch() 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. Dentro de tu controlador, puedes tomar las medidas adecuadas, 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.

Aquí encontrarás una publicación dedicada a algunas de las acciones que puedes realizar con la API de notificaciones.

Cómo anular la suscripción del dispositivo de un usuario

Suscribirte al dispositivo de un usuario y que reciba mensajes push es fácil, pero ¿cómo puedes anular su suscripción?

Los elementos principales necesarios para cancelar la suscripción del dispositivo de un usuario son llamar al método unsubscribe() en el objeto PushSubscription y quitar el extremo de tus servidores (solo para que no envíes mensajes push que sepas que no se recibirán). El siguiente código hace exactamente lo siguiente:

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);
        });
    });
}

Mantén la suscripción actualizada

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

Las suscripciones también pueden perder sincronización 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 automática de la suscripción. Para controlar estos casos, verifica el resultado de serviceWorkerRegistration.pushManager.getSubscription() periódicamente (p.ej., cuando se carga la página) y sincronízalo con el servidor. También te recomendamos que te vuelvas a suscribir 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 hacer 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 generan una implementación completa de los mensajes push en la Web en Chrome 46. Aún hay funciones especificadas que facilitarán las cosas (como una API estándar para activar mensajes push), pero esta versión te permite comenzar a compilar mensajes push en tus apps web hoy mismo.

Cómo depurar tu app web

Mientras implementas los mensajes push, los errores se encontrarán en uno de dos lugares: tu página o tu service worker.

Los errores de la página se pueden depurar con DevTools. Para depurar problemas del trabajador de servicio, tienes dos opciones:

  1. Ve a chrome://inspect > Service workers. Esta vista no proporciona mucha información, aparte de los service workers que se están ejecutando actualmente.
  2. Ve a chrome://serviceworker-internals y, desde allí, puedes ver el estado de los service workers y los errores, si los hay. Esta página es temporal hasta que DevTools tenga un conjunto de funciones similar.

Una de las mejores sugerencias que puedo darle a cualquier persona que sea nueva en el uso de los service workers es usar la casilla de verificación llamada "Abrir la ventana de DevTools y pausar la ejecución de JavaScript en el inicio del service worker para depurar". Esta casilla de verificación agregará una pausa al comienzo de tu service worker y detendrá la ejecución. Esto te permitirá reanudar o recorrer la secuencia de comandos del service worker y ver si encuentras algún problema.

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

Si parece haber un problema entre FCM y el evento push de tu trabajador de servicio, no hay mucho que puedas hacer para depurar el problema, ya que no hay forma de ver si Chrome recibió algo. Lo más importante es garantizar que la respuesta de FCM se realice correctamente cuando tu servidor realice una llamada a la API. Tendrá el siguiente aspecto:

{"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, no es evidente cómo depurar los trabajadores de servicio en Chrome para Android. Debes navegar a chrome://inspect, buscar tu dispositivo y encontrar un elemento de lista con el nombre "Worker pid:….", que tiene la URL de tu service worker.

Captura de pantalla que muestra dónde se alojan los trabajadores del servicio en Chrome Inspect

UX para notificaciones push

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 se diferenciarán de otras implementaciones del navegador.

Protocolo y extremos de Web Push

La belleza del estándar de la API de Push es que deberías poder tomar el extremo, pasarlo a tu servidor y enviar mensajes push mediante la implementación del Protocolo de notificaciones push web.

El Protocolo de notificaciones push web es un nuevo estándar que los proveedores de notificaciones push pueden implementar, lo que permite que los desarrolladores no tengan que preocuparse por quién es el proveedor de notificaciones push. La idea es que esto evite la necesidad de registrarse para obtener claves de API y enviar datos con formato especial, como lo tienes que hacer con FCM.

Chrome fue el primer navegador en implementar la API de Push, y FCM no es compatible con el protocolo de notificaciones web, por lo que Chrome requiere la gcm_sender_id y debes usar la API de REST para FCM.

El objetivo final de Chrome es usar el protocolo de notificaciones 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?

Actualmente, Firefox Nightly está trabajando en la función push y es probable que sea el primer navegador que implemente el Protocolo de notificaciones 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 en la Web y en la nativa?

Por el momento, no hay una solución para este problema, 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 IDs de suscripción de la app nativa y la app web, y decidir a cuál enviar un mensaje push. Puedes hacerlo a través del tamaño de la pantalla, el modelo del dispositivo o compartiendo una clave generada entre la app web y la nativa, pero cada enfoque tiene sus ventajas y desventajas.

¿Por qué necesito un gcm_sender_id?

Esto es necesario para que Chrome, Opera para Android y el navegador Samsung puedan usar la API de Firebase Cloud Messaging (FCM). El objetivo es usar el Protocolo de notificaciones push web cuando se finalice el estándar y FCM pueda admitirlo.

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

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

¿Qué sucede si no necesito la entrega de eventos en segundo plano?

Si no necesitas la entrega en segundo plano, los sockets web son una excelente opción.

¿Cuándo puedo usar el envío de notificaciones push sin mostrarlas (es decir, el envío de notificaciones push en segundo plano y silenciosas)?

Aún no hay un cronograma para saber cuándo estará disponible, pero hay un intento de implementar la sincronización en segundo plano y, si bien no se decidió ni se especificó, se está analizando la posibilidad de habilitar el envío silencioso con la sincronización en segundo plano.

¿Por qué se requiere HTTPS? ¿Cómo puedo solucionar este problema durante el desarrollo?

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

¿Cómo es la compatibilidad con navegadores?

Chrome es compatible con la versión estable, y Mozilla está trabajando en el envío en Firefox Nightly. Consulta el error de implementación de 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, no es posible, pero planeamos agregar compatibilidad para obtener una lista de las notificaciones visibles actualmente. Si tienes un caso de uso para establecer un vencimiento para la notificación después de que se muestra creada, nos encantaría saber cuál es, así que 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, 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?

En esta publicación, se describen algunas limitaciones:

  • El uso de Chrome de la CCM como servicio push crea una serie de requisitos de propiedad. Estamos trabajando juntos para ver si se pueden levantar algunos de ellos en el futuro.
  • Debes mostrar una notificación cuando recibes un mensaje push.
  • Chrome para computadoras de escritorio tiene la advertencia de que, si no se ejecuta, no se recibirán los mensajes push. Esto difiere de ChromeOS y Android, en los que siempre se recibirán los 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. Obtén más información aquí.

¿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 están controladas por un service worker. Aquí puedes obtener más información sobre el tema.

¿Qué sucede si una notificación está desactualizada cuando el dispositivo del usuario recibe la notificación push?

Siempre debes mostrar una notificación cuando recibas un mensaje push. En el caso de que quieras enviar una notificación, pero solo sea útil durante un período determinado, puedes usar el parámetro "time_to_live" en CCM para que FCM no envíe el mensaje push si pasa el tiempo de vencimiento.

Aquí puedes consultar más detalles al respecto.

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

FCM tiene un parámetro "collapse_key" que puedes usar para indicarle a FCM que reemplace cualquier mensaje pendiente que tenga la misma "collapse_key" con el mensaje nuevo.

Puedes obtener más detalles aquí.