Notificaciones push en la Web abierta

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

Las notificaciones push permiten a los usuarios habilitar las actualizaciones oportunas de sus sitios favoritos 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 notificación están disponibles para los desarrolladores.

La API de Push en Chrome se basa en diferentes tecnologías, incluidos los manifiestos de apps web y los Service Workers. En esta publicación, veremos cada una de estas tecnologías, pero solo lo mínimo para poner en marcha los mensajes push. 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 futuras versiones de Chrome y, por último, tendremos una sección de Preguntas frecuentes.

Implementación de Push Messaging 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

Depende 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.

A continuación, se muestra un ejemplo de cómo puedes registrar un service worker en tu app web. Una vez que el registro se haya completado correctamente, llamaremos 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 en botones suscribe al usuario a mensajes push o anula la suscripción. isPushEnabled es una variable global que simplemente realiza un seguimiento de si los mensajes push están suscritos o no. Se hará referencia a ellas en 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 controlar un mensaje push. Aquí 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 para tu sitio y que se mantenga actualizada con los cambios que se produzcan. En otras palabras, si habilitan los mensajes push para tu sitio, abandonan y regresan 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, puede que pienses que solo hay dos estados para tratar: habilitados o inhabilitados. Sin embargo, hay otros estados relacionados con las notificaciones que debes tener en cuenta.

Diagrama en el que se destacan las diferentes consideraciones y el estado de la instalación 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 los mensajes push están suscritos o no.

Dado que la mayoría de estas verificaciones hacen que nuestra IU se inhabilite, debes configurar el estado inicial como inhabilitada. De esta manera, también se evita cualquier confusión en caso de que haya un problema con el código JavaScript de tu página, por ejemplo, el archivo JS no se puede descargar o 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 registrar el 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);
        });
    });
}

Breve descripción general de estos pasos:

  • Comprobamos que showNotification esté disponible en el prototipo ServiceWorkerRegistration. Sin ella, no podremos mostrar una notificación de nuestro service worker cuando se reciba un mensaje push.
  • Verificamos cuál es el elemento Notification.permission actual para asegurarnos de que no sea "denied". Si se rechaza un permiso, significa que no puedes mostrar notificaciones hasta que el usuario cambie el permiso de forma manual en el navegador.
  • Para verificar si se admiten los mensajes 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 que los mensajes push ya están habilitados o no. Veremos qué detalles existen en el objeto de suscripción más adelante en este artículo.

Esperamos hasta que se resuelva navigator.serviceWorker.ready para buscar una suscripción y habilitar el botón push, ya que solo podrás suscribirte a los mensajes push una vez que esté activo el service worker.

El siguiente paso es controlar cuándo el usuario quiere habilitar mensajes push. Sin embargo, antes de que podamos 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 Chrome, Opera para Android y el navegador Samsung, que usan FCM. Analizaremos cómo funcionaría esto en otros navegadores más adelante en el artículo.

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 del nuevo proyecto de Firebase

Agrega un nombre de proyecto, crea el proyecto y se te redireccionará al panel del proyecto:

Página principal del proyecto de Firebase

Desde este panel, haz clic en el ícono de ajustes junto al nombre de tu proyecto en la esquina superior izquierda y selecciona “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 ingresar en el manifiesto de la app web en la siguiente sección.

Agrega un manifiesto de app web

Para las notificaciones push, debemos agregar un archivo de manifiesto con un campo gcm_sender_id a fin de que la suscripción de envío se realice de forma correcta. Este parámetro solo es obligatorio para Chrome, Opera para Android y el navegador Samsung para que puedan usar FCM / GCM.

Estos navegadores usan el 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 tu ID de remitente coincida con la clave de API correspondiente. Además, este usuario permite que tu servidor le envíe mensajes push.

A continuación, encontrarás un archivo de manifiesto muy sencillo:

{
    "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 HTML con la siguiente etiqueta en el encabezado de tu 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 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 de origen para enviar notificaciones push. Sin este permiso, no podrás suscribirte correctamente.

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

El extremo se debe guardar 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 para recibir 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 próxima sección), se enviará un evento push en tu service worker, momento en el cual 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 predefinido, texto del cuerpo, ícono y etiqueta de notificación. Un detalle que se debe 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 puede considerarse que mantiene activo el service worker) hasta que la promesa se establezca. En este caso, la promesa que se pasa a event.waitUntil es la 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 si mostramos notificaciones con la misma etiqueta, el navegador mostrará la primera notificación y la reemplazará por la segunda cuando se reciba el mensaje push.

Si deseas mostrar varias notificaciones a la vez, usa una etiqueta diferente o no usa ninguna. Más adelante en esta publicación, veremos un ejemplo más completo de cómo mostrar una notificación. Por ahora, simplificamos el proceso y veamos si esta notificación muestra el envío de un mensaje push.

Cómo enviar un mensaje push

Nos hemos suscrito a los mensajes push y nuestro service worker está listo para mostrar una notificación, así que 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 para FCM es especial. Tiene un parámetro al final de la URL, que es una 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

El registration_id sería el 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, simplemente obtendrías un extremo, llamarías a ese extremo 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 registration_id. Para hacer esto en Python, podrías hacer algo como 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. Puedes encontrar los 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 apropiado, asegúrate de que el usuario haya otorgado permiso para tu proyecto y, por último, 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 como JSON o datos de formularios
  • Un array de registration_ids: Estos son los ID de registro que extraerías de los extremos de tus usuarios.

Consulta la documentación sobre cómo enviar mensajes push desde tu servidor. Sin embargo, si quieres verificar tu service worker rápidamente, 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 de cURL por los tuyos y ejecútalos desde una terminal.

Deberías ver una notificación gloriosa:

    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 de autorización 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 condicionalmente el encabezado y dar formato al cuerpo de POST. Para otros navegadores (y, con suerte, Chrome en el futuro), deberás implementar el protocolo de envío 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 el servidor antes de enviarse 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 push. Esto también brinda protección contra otras vulnerabilidades, como la validación deficiente de certificados HTTPS y los ataques de intermediarios entre tu servidor y el proveedor de envío. Sin embargo, aún no se admite esta encriptación, 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 los ejemplos, no es suficiente para cubrir un caso de uso real.

Desde una perspectiva realista, la mayoría de las personas querrán obtener cierta información de su servidor antes de mostrar la notificación. 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, obtenemos 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 destacar que event.waitUntil() toma una promesa que da como resultado la 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.

Cómo 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 en el service worker. Dentro de tu controlador, puedes realizar las acciones 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 existe, y, de lo contrario, se abre una nueva.

Encontrarás una entrada dedicada a algunas de las acciones que puedes hacer con la API de notificaciones aquí.

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

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

Para anular la suscripción del dispositivo de un usuario, los principales requisitos son 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 no se sincronicen entre FCM y tu servidor. Asegúrate de que tu servidor analice el cuerpo de la respuesta del POST de envío de la API de FCM y busque los resultados de error:NotRegistered y canonical_id, como se explica en la documentación de FCM.

Es posible que las suscripciones también se desincronizan entre el service worker y tu servidor. Por ejemplo, después de suscribirte o anular la suscripción con éxito, una conexión de red inestable puede impedir que actualices tu servidor, o un usuario podría revocar el permiso de notificaciones, lo que activa una anulación automática de suscripción. Para controlar esos casos, verifica el resultado de serviceWorkerRegistration.pushManager.getSubscription() de forma periódica (p.ej., durante la carga de la página) y sincronízalo con el servidor. También puedes 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 con errores 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 los mensajes push en la Web en Chrome 46. Aún hay funciones específicas 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 aplicación web

Cuando implementas mensajes push, los errores se encuentran en uno de estos dos lugares: tu página o tu service worker.

Los errores de la página se pueden depurar con DevTools. Para depurar problemas del service worker, 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 ver los errores, si los hay. Esta página es temporal hasta que Herramientas para desarrolladores tengan un conjunto de funciones similar.

Una de las mejores sugerencias que puedo darle a cualquier persona que no tenga experiencia con los service workers es que utilice la casilla de verificación “Abrir ventana de Herramientas para desarrolladores y pausar la ejecución de JavaScript en el inicio del service worker para depurar”. Esta casilla de verificación agregará un punto de interrupción al comienzo del service worker y de la pausa de la ejecución, lo que te permite reanudarla o revisarla para ver si se produjo algún problema.

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

Si parece que hay un problema entre FCM y el evento push del service worker, no hay mucho que puedas hacer para depurar el problema, ya que no hay forma de ver si Chrome recibió algún mensaje. El aspecto clave que debes asegurarte es que la respuesta de FCM sea correcta cuando tu servidor realice una llamada a la API. Se verá de la siguiente manera:

{"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, eso sugiere que hay algún problema con el ID de registro de FCM y que el mensaje push no se está enviando a Chrome.

Depuración de Service Workers en Chrome para Android

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

Captura de pantalla en la que se muestra la ubicación de los service workers en Chrome para inspeccionar

UX para notificaciones push

El equipo de Chrome creó un documento con recomendaciones para la UX de las notificaciones push, así como un documento en el que se abordan algunos de los casos extremos en los que se trabaja con este tipo de notificaciones.

El futuro de los mensajes 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 conocer y en qué se diferenciarán de otras implementaciones del navegador.

Protocolo de envío web y extremos

El atractivo del estándar de la API de Push es que deberías poder tomar el extremo, pasarlo a tu servidor y enviar mensajes push con la implementación del protocolo de envío web.

El protocolo de envío web es un nuevo estándar que pueden implementar los proveedores de envío, lo que permite a los desarrolladores no tener que preocuparse por quién es el proveedor de servicios push. La idea es que esto evita la necesidad de registrarse para obtener claves de API y enviar datos con un 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 inserción web, por lo que Chrome requiere el gcm_sender_id y necesitas usar la API de REST para FCM.

El objetivo final de Chrome es avanzar hacia el uso del protocolo web push 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 la carga útil de manera específica y agregar la clave de autorización.

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

Por el momento, Firefox Nightly está trabajando en las funciones push y es probable que sea el primer navegador en implementar el protocolo web push.

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 las notificaciones duplicadas si mi presencia en la Web tiene varios orígenes, o si tengo presencia nativa y en la Web?

Por el momento, no hay una solución para esto, 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 de la aplicación web y decidir a cuál enviar un mensaje push. Puedes hacerlo mediante el tamaño de la pantalla, el modelo del dispositivo y el uso compartido de una clave generada entre la aplicación web y la aplicación 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 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 sockets web o eventos enviados por el servidor (EventSource)?

La ventaja de usar mensajes push es que, aunque la página esté cerrada, se despertará al service worker y podrá mostrarle una notificación. Los sockets web y EventSource se cierran la conexión cuando se cierra la página o el navegador.

¿Qué sucede si no necesito que se entreguen eventos en segundo plano?

Si no necesita entregas en segundo plano, los sockets web son una excelente opción.

¿Cuándo puedo usar push sin mostrar notificaciones (es decir, notificaciones push silenciosas 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, aunque no se decide ni se especifica, hay un debate sobre cómo habilitar el envío silencioso con sincronización en segundo plano.

¿Por qué esto requiere HTTPS? ¿Cómo evito 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 sea de un ataque de intermediario. Por el momento, eso significa usar HTTPS en sitios activos, aunque localhost funcionará durante el desarrollo.

¿Cómo es la compatibilidad con navegadores?

Chrome es compatible con su versión estable y Mozilla está trabajando en el programa en Nightly de Firefox. Consulta el error 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 en ese momento. Si tienes un caso de uso en el que establecer un vencimiento para la notificación una vez creada, cuéntanos qué sucede. Agrega un comentario y 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 importa cuánto tiempo la notificación 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?

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

  • El uso que hace Chrome de CCM como servicio push crea varios requisitos de propiedad. Estamos trabajando juntos para ver si algunas de estas se pueden mejorar en el futuro.
  • Debes mostrar una notificación cuando recibas un mensaje push.
  • En Chrome para computadoras de escritorio, se tiene la advertencia de que, si Chrome no se está ejecutando, los mensajes push no se recibirán. Esto difiere de ChromeOS y Android, en los que los mensajes push siempre se recibirán.

¿No deberíamos usar la API de Permissions?

La API de Permission se implementa en Chrome, pero no siempre 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 para el momento en que el dispositivo del usuario recibe el mensaje push?

Debes mostrar siempre una notificación cuando recibas un mensaje push. Si deseas enviar una notificación, pero es ú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 la hora de vencimiento.

Puedes obtener más detalles aquí.

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

FCM tiene un parámetro “contraer_key” que puedes usar para indicarle que reemplace cualquier mensaje pendiente que tenga la misma clave “contraer_clave” por el mensaje nuevo.

Puedes obtener más detalles aquí.