Cómo usar un Service Worker para administrar notificaciones

Kate Jeffreys
Kate Jeffreys

En este codelab, usarás un trabajador de servicio para administrar las notificaciones. En las instrucciones que se incluyen aquí, se da por sentado que ya conoces los trabajadores del servicio y los conceptos básicos para solicitar permisos de notificación y enviar notificaciones. Si necesitas hacer un repaso sobre las notificaciones, consulta el codelab Comienza a usar la API de Notifications. Para obtener más información sobre los trabajadores de servicio, consulta la Introducción a los trabajadores de servicio de Matt Gaunt.

Remezcla la app de ejemplo y mírala en una pestaña nueva

Las notificaciones se bloquean automáticamente en la app incorporada de Glitch, por lo que no podrás obtener una vista previa de la app en esta página. En su lugar, haz lo siguiente:

  1. Haz clic en Remix para editar para que el proyecto se pueda editar.
  2. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.

El problema se debería abrir en una nueva pestaña de Chrome.

A medida que trabajes en este codelab, realiza cambios en el código de la Glitch incorporada en esta página. Actualiza la pestaña nueva con la app publicada para ver los cambios.

Familiarízate con la app de ejemplo y el código de partida

Primero, observa la app en vivo en la nueva pestaña de Chrome:

  1. Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  2. Haz clic en la pestaña Consola.

  3. Asegúrate de que la opción Info esté seleccionada en el menú desplegable Levels junto al cuadro Filter.

  4. En la consola de DevTools de tu app publicada, deberías ver un mensaje de consola:

    TODO: Implement getRegistration().

    Este es un mensaje de un stub de función que implementarás en este codelab.

Ahora, veamos el código de la app de ejemplo en el Glitch incorporado en esta página.

  1. En el Glitch incorporado, observa public/index.js:

    • Hay cuatro stubs para las funciones que implementarás: registerServiceWorker, getRegistration, unRegisterServiceWorker y sendNotification.

    • La función requestPermission solicita el permiso del usuario para enviar notificaciones. Si completaste el codelab Cómo comenzar a usar la API de Notifications, notarás que aquí se usa su función requestPermission. La única diferencia es que ahora también se actualiza la interfaz de usuario después de resolver la solicitud de permiso.

    • La función updateUI actualiza todos los botones y mensajes de la app.

    • La función initializePage realiza la detección de funciones para la capacidad de trabajador de servicio en el navegador y actualiza la interfaz de usuario de la app.

    • La secuencia de comandos espera hasta que la página se cargue y, luego, la inicializa.

  2. En Glitch incorporado, abre public/service-worker.js.

    Como el nombre lo sugiere, agregarás código a la app para registrar el archivo como service worker.

    Aunque la app aún no usa el archivo, contiene un código de inicio que imprimirá un mensaje en la consola cuando se active el trabajador de servicio.

    Agregarás código a public/service-worker.js para controlar las notificaciones cuando el trabajador de servicio las reciba.

Registra el service worker

En este paso, escribirás código que se ejecutará cuando el usuario haga clic en Register service worker en la IU de la app. Este código registrará public/service-worker.js como un service worker.

  1. En el editor Glitch incorporado, abre public/index.js. Reemplaza la función registerServiceWorker por el siguiente código:

    // Use the Service Worker API to register a service worker.
    async
    function registerServiceWorker() {
      await navigator
    .serviceWorker.register('./service-worker.js')
      updateUI
    ();
    }

    Ten en cuenta que registerServiceWorker usa la declaración async function para que el manejo de promesas sea más conveniente. Esto te permite await el valor resuelto de una Promise. Por ejemplo, la función anterior espera el resultado del registro de un service worker antes de actualizar la IU. Consulta await en MDN para obtener más información.

  2. Ahora que el usuario puede registrar un service worker, puedes obtener una referencia al objeto de registro del service worker. En public/index.js, reemplaza la función getRegistration por el siguiente código:

    // Get the current service worker registration.
    function getRegistration() {
     
    return navigator.serviceWorker.getRegistration();
    }

    La función anterior usa la API de Service Worker para obtener el registro de service worker actual, si existe. Esto hace que obtener una referencia al registro del servicio de trabajo sea un poco más conveniente.

  • Para completar la funcionalidad de registro del trabajador de servicio, agrega código para anular el registro del trabajador de servicio. Reemplaza la función unRegisterServiceWorker por el siguiente código:

    // Unregister a service worker, then update the UI.
    async
    function unRegisterServiceWorker() {
     
    // Get a reference to the service worker registration.
      let registration
    = await getRegistration();
     
    // Await the outcome of the unregistration attempt
     
    // so that the UI update is not superceded by a
     
    // returning Promise.
      await registration
    .unregister();
      updateUI
    ();
    }

En la pestaña en la que ves la app publicada, vuelve a cargar la página. Los botones Register service worker y Unregister service worker ahora deberían funcionar.

Cómo enviar notificaciones al service worker

En este paso, escribirás código que se ejecutará cuando el usuario haga clic en Enviar una notificación en la IU de la app. Este código creará una notificación, verificará que se haya registrado un trabajador de servicio y, luego, le enviará la notificación con su método postMessage.

En el editor Glitch incorporado, abre public/index.js y reemplaza la función sendNotification por el siguiente código:

// Create and send a test notification to the service worker.
async
function sendNotification() {
 
// Use a random number as part of the notification data
 
// (so you can tell the notifications apart during testing!)
  let randy
= Math.floor(Math.random() * 100);
  let notification
= {
    title
: 'Test ' + randy,
    options
: { body: 'Test body ' + randy }
 
};
 
// Get a reference to the service worker registration.
  let registration
= await getRegistration();
 
// Check that the service worker registration exists.
 
if (registration) {
   
// Check that a service worker controller exists before
   
// trying to access the postMessage method.
   
if (navigator.serviceWorker.controller) {
      navigator
.serviceWorker.controller.postMessage(notification);
   
} else {
      console
.log('No service worker controller found. Try a soft reload.');
   
}
 
}
}

Esto es lo que hace ese código:

  • sendNotification es una función asíncrona, por lo que puedes usar await para obtener una referencia al registro del service worker.

  • El método postMessage del service worker envía datos de la app al service worker. Consulta la documentación de MDN sobre postMessage para obtener más información.

  • El código verifica la presencia de la propiedad navigator.serviceWorker.controller antes de intentar acceder a la función postMessage. navigator.serviceWorker.controller será null si no hay un service worker activo o si la página se actualizó de forma forzosa (Shift+Reload). Consulta la documentación del controlador de ServiceWorker en MDN para obtener más información.

Controla las notificaciones en el service worker

En este paso, escribirás código en el servicio de trabajo que controlará los mensajes que se publiquen en él y mostrará notificaciones al usuario.

En el editor Glitch incorporado, abre public/service-worker.js. Agrega el siguiente código al final del archivo:

// Show notification when received
self
.addEventListener('message', (event) => {
  let notification
= event.data;
  self
.registration.showNotification(
    notification
.title,
    notification
.options
 
).catch((error) => {
    console
.log(error);
 
});
});

Aquí tienes una explicación breve:

  • self es una referencia al propio servicio de trabajo.

  • Si bien el trabajador del servicio ahora controla la visualización de notificaciones, la IU principal de la app sigue siendo responsable de obtener el permiso de notificación del usuario. Si no se otorga el permiso, se rechaza la promesa que muestra showNotification. El código anterior usa un bloque catch para evitar un error de rechazo Promise no detectado y manejarlo de forma más fluida.

Si tienes problemas, consulta glitch.com/edit/#!/codelab-notifications-service-worker-completed para ver el código completo.

Continúa con el siguiente codelab de esta serie: Compila un servidor de notificaciones push.