Agrega notificaciones push a una app web

1. Descripción general

Los mensajes push proporcionan una forma simple y eficaz de volver a atraer a tus usuarios. En este codelab, aprenderás a agregar notificaciones push a tu app web.

Qué aprenderás

  • Cómo suscribir o anular la suscripción de un usuario a mensajes push
  • Cómo manejar los mensajes push entrantes
  • Cómo mostrar una notificación
  • Cómo responder a clics de notificaciones

Requisitos

  • Chrome 52 o superior
  • Servidor web para Chrome o el servidor web que elijas
  • Un editor de texto
  • Conocimientos básicos de HTML, CSS, JavaScript y Herramientas para desarrolladores de Chrome
  • El código de muestra (consulta Preparación).

2. Prepárate

Descarga el código de muestra

Hay dos maneras de obtener el código de muestra de este codelab:

  • Clona el repositorio de Git:
git clone https://github.com/GoogleChrome/push-notifications.git
  • Descarga el archivo ZIP:

Descargar código fuente

Si descargas la fuente como un archivo ZIP, cuando lo descomprimes, obtienes una carpeta raíz push-notifications-master.

Instala y verifica el servidor web

Aunque puedes usar tu propio servidor web, este codelab está diseñado para funcionar bien con la app Web Server for Chrome. Si aún no tienes esa app instalada, puedes descargarla desde Chrome Web Store:

Después de instalar la app Web Server for Chrome, haz clic en el acceso directo Apps en la barra de favoritos:

946bcaaad66e5c8e.png

En la ventana Apps, haz clic en el ícono de Web Server:

9f3c21b2cf6cbfb5.png

A continuación, verás este diálogo, que te permite configurar tu servidor web local:

73543edeb27c3d6f.png

Haz clic en el botón Choose folder y selecciona la carpeta app en la carpeta push-notifications que descargaste. Esto te permite entregar tu trabajo en curso a través de la URL que se muestra en la sección URL del servidor web del diálogo.

En Opciones, marca la casilla junto a Mostrar automáticamente index.html, como se muestra a continuación:

5ac11bca86ce7369.png

Luego, detén y reinicia el servidor deslizando el botón de activación Web Server: STARTED hacia la izquierda y, luego, de nuevo hacia la derecha.

d42f87972f9fec24.png

Haz clic en la URL del servidor web para visitar tu sitio en tu navegador web. Deberías ver una página como la siguiente, aunque es posible que tu versión muestre 127.0.0.1:8887 como la dirección:

00-push-codelab.png

Siempre actualiza el service worker

Durante el desarrollo, es útil asegurarse de que tu service worker siempre esté actualizado y tenga los cambios más recientes.

Para configurar esta opción en Chrome, haz lo siguiente:

  1. Ve a la pestaña Push Codelab.
  2. Abre Herramientas para desarrolladores: Ctrl-Mayúsculas-I en Windows y Linux, Cmd-Opción-I en macOS.
  3. Selecciona el panel Application, haz clic en la pestaña Service Workers y marca la casilla de verificación Update on Reload. Cuando se habilita esta casilla de verificación, el service worker se actualiza forzosamente cada vez que se vuelve a cargar la página.

e7d384fb77885b99.png

3. Registra un service worker

Código completo

En tu directorio app, observa que tienes un archivo vacío llamado sw.js. Este archivo será tu service worker. Por ahora, puede permanecer vacío. Más adelante, le agregarás código.

Primero, debes registrar este archivo como tu service worker.

Tu página de app/index.html carga scripts/main.js. Registras tu service worker en este archivo JavaScript.

Agrega el siguiente código a scripts/main.js:

if ('serviceWorker' in navigator && 'PushManager' in window) {
  console.log('Service Worker and Push are supported');

  navigator.serviceWorker.register('sw.js')
  .then(function(swReg) {
    console.log('Service Worker is registered', swReg);

    swRegistration = swReg;
  })
  .catch(function(error) {
    console.error('Service Worker Error', error);
  });
} else {
  console.warn('Push messaging is not supported');
  pushButton.textContent = 'Push Not Supported';
}

Este código verifica si los service workers y la mensajería push son compatibles con tu navegador. Si son compatibles, el código registra tu archivo sw.js.

Probar

Para verificar los cambios, actualiza la pestaña Push Codelab en el navegador.

Busca una Service Worker is registered message en la consola en las Herramientas para desarrolladores de Chrome, como se muestra a continuación:

5d7ad383d6f235d5.png

Obtener claves del servidor de la aplicación

Para trabajar con este codelab, debes generar claves de servidor de aplicaciones. Puedes hacerlo en el sitio complementario: web-push-codelab.glitch.me

Aquí puedes generar un par de claves pública y privada.

push-codelab-04-companion.png

Copia tu clave pública en scripts/main.js y reemplaza el valor <Your Public Key>:

const applicationServerPublicKey = '<Your Public Key>';

Importante: Nunca debes guardar tu clave privada en una app web.

4. Inicializa el estado

Código completo

En este momento, el botón Habilitar de la aplicación web está inhabilitado y no se puede hacer clic en él. Esto se debe a que es una buena práctica inhabilitar el botón push de forma predeterminada y habilitarlo después de saber que la mensajería push es compatible con el navegador y que puedas verificar si el usuario está suscrito actualmente al servicio de mensajería o no.

Deberás crear dos funciones en scripts/main.js:

  • initializeUI para comprobar si el usuario está suscrito
  • updateBtn, para habilitar el botón y cambiar el texto según si el usuario está suscrito o no

Agrega una función initializeUI a main.js de la siguiente manera:

function initializeUI() {
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

Tu nuevo método usa el swRegistration del paso anterior, obtiene la propiedad pushManager de él y llama a getSubscription() para eso.

pushManager getSubscription() muestra una promesa que se resuelve con la suscripción actual, si existe una. De lo contrario, muestra null. De esta manera, puedes verificar si el usuario ya está suscrito, establecer el valor de isSubscribed y, luego, llamar a updateBtn() para actualizar el botón.

Agrega la función updateBtn() a main.js:

function updateBtn() {
  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

Esta función habilita el botón y cambia su texto en función de si el usuario está suscrito o no.

Lo último que debes hacer es llamar a initializeUI() cuando tu service worker está registrado en main.js:

navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
  console.log('Service Worker is registered', swReg);

  swRegistration = swReg;
  initializeUI();
})

Probar

Actualiza la pestaña Push Codelab. Deberías ver que el botón Enable Push Messaging ahora está habilitado (puedes hacer clic en él) y deberías ver User is NOT subscribed en la consola.

a1553f4a0483d227.png

A medida que avances en el resto de este codelab, deberías ver que el texto del botón cambia cada vez que te suscribes o anulas la suscripción.

5. Suscribir al usuario

Código completo

Por el momento, el botón Enable Push Messaging no hace mucho. Sin embargo, podemos solucionarlo.

En la función initializeUI(), agrega un objeto de escucha de clics para tu botón:

function initializeUI() {
  pushButton.addEventListener('click', function() {
    pushButton.disabled = true;
    if (isSubscribed) {
      // TODO: Unsubscribe user
    } else {
      subscribeUser();
    }
  });

  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    updateSubscriptionOnServer(subscription);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

Cuando el usuario hace clic en el botón, lo inhabilitas solo para asegurarte de que el usuario no pueda hacer clic en él una segunda vez, ya que suscribirse a la mensajería push puede llevar tiempo.

Luego, llamarás a subscribeUser() si el usuario no está suscrito en ese momento. Para ello, deberás pegar el siguiente código en scripts/main.js:

function subscribeUser() {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
  .then(function(subscription) {
    console.log('User is subscribed.');

    updateSubscriptionOnServer(subscription);

    isSubscribed = true;

    updateBtn();
  })
  .catch(function(error) {
    console.error('Failed to subscribe the user: ', error);
    updateBtn();
  });
}

Analicemos lo que hace este código y cómo está suscribiendo al usuario a mensajes push.

Primero, toma la clave pública del servidor de aplicaciones, que está codificada a través de una URL en Base64, y la conviertes en un UInt8Array, ya que esta es la entrada esperada de la llamada a subscribe(). La función urlB64ToUint8Array() está en la parte superior de scripts/main.js.

Después de convertir el valor, llama al método subscribe() en el pushManager de tu service worker y pasa la clave pública del servidor de tu aplicación y el valor userVisibleOnly: true.

const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})

El parámetro userVisibleOnly es una garantía de que mostrarás una notificación cada vez que se envíe un mensaje push. Actualmente, este valor es obligatorio y debe ser verdadero.

Llamar a subscribe() muestra una promesa que se resolverá después de los siguientes pasos:

  1. El usuario otorgó permiso para mostrar notificaciones.
  2. El navegador envió una solicitud de red a un servicio push para obtener los datos necesarios y generar un PushSubscription.

La promesa subscribe() se resolverá con PushSubscription si estos pasos se realizaron de forma correcta. Si el usuario no otorga permiso o si hay algún problema para suscribirlo, la promesa se rechazará con un error. Esto te proporciona la siguiente cadena de promesa en tu codelab:

swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})
.then(function(subscription) {
  console.log('User is subscribed.');

  updateSubscriptionOnServer(subscription);

  isSubscribed = true;

  updateBtn();

})
.catch(function(err) {
  console.log('Failed to subscribe the user: ', err);
  updateBtn();
});

De esta manera, obtienes una suscripción y tratas al usuario como suscrito o detectas un error y lo registras en la consola. En ambos casos, debes llamar a updateBtn() para asegurarte de que el botón se vuelva a habilitar y tenga el texto adecuado.

En una aplicación real, la función updateSubscriptionOnServer() es donde enviarías tus datos de suscripción a un backend, pero para el codelab solo muestras la suscripción en tu IU. Agrega la siguiente función a scripts/main.js:

function updateSubscriptionOnServer(subscription) {
  // TODO: Send subscription to application server

  const subscriptionJson = document.querySelector('.js-subscription-json');
  const subscriptionDetails =
    document.querySelector('.js-subscription-details');

  if (subscription) {
    subscriptionJson.textContent = JSON.stringify(subscription);
    subscriptionDetails.classList.remove('is-invisible');
  } else {
    subscriptionDetails.classList.add('is-invisible');
  }
}

Probar

Ve a la pestaña Push Codelab, actualiza la página y haz clic en el botón. Deberías ver una solicitud de permiso como la siguiente:

fcc61267a0194e81.png

Si otorgas el permiso, deberías ver User is subscribed registrado en la consola. El texto del botón cambiará a Disable Push Messaging y podrás ver la suscripción como datos JSON en la parte inferior de la página.

5c5505f2ead037c.png

6. Controla el permiso denegado

Código completo

Algo que aún no has manejado es lo que sucede si el usuario bloquea la solicitud de permiso. Esto requiere una consideración especial, ya que, si el usuario bloquea el permiso, tu app web no podrá volver a mostrar la solicitud de permiso ni podrá suscribir al usuario. Al menos debes inhabilitar el botón push para que el usuario sepa que no se puede usar.

El lugar obvio para controlar esta situación es la función updateBtn(). Lo único que debes hacer es verificar el valor Notification.permission, de la siguiente manera:

function updateBtn() {
  if (Notification.permission === 'denied') {
    pushButton.textContent = 'Push Messaging Blocked';
    pushButton.disabled = true;
    updateSubscriptionOnServer(null);
    return;
  }

  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

Sabes que, si el permiso es denied, no se podrá suscribir el usuario y no podrás hacer nada más, por lo que la mejor opción es inhabilitar el botón de forma permanente.

Probar

Como ya otorgaste el permiso para tu aplicación web en el paso anterior, debes hacer clic en la i, en un círculo de la barra de URL, y cambiar el permiso de Notificaciones a Use global default (Ask).

54495592074f10ae.png

Después de cambiar este parámetro, actualiza la página, haz clic en el botón Enable Push Messaging y selecciona Block en el diálogo del permiso. El botón se inhabilitará y mostrará el texto Push Messaging Blocked.

d4cf22468f6defda.png

Con este cambio, ahora puedes suscribir al usuario, teniendo en cuenta las posibles situaciones de permisos.

7. Controla un evento push

Código completo

Antes de aprender cómo enviar un mensaje push desde tu backend, debes considerar lo que realmente sucederá cuando un usuario suscrito reciba un mensaje push.

Cuando activas un mensaje push, el navegador recibe el mensaje push, determina para qué service worker es el push, activa ese service worker y despacha un evento push. Debes escuchar este evento y mostrar una notificación como resultado.

Agrega el siguiente código a tu archivo sw.js:

self.addEventListener('push', function(event) {
  console.log('[Service Worker] Push Received.');
  console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

  const title = 'Push Codelab';
  const options = {
    body: 'Yay it works.',
    icon: 'images/icon.png',
    badge: 'images/badge.png'
  };

  event.waitUntil(self.registration.showNotification(title, options));
});

Revisemos este código paso a paso. Agregarás un objeto de escucha de eventos para escuchar los eventos push en tu service worker:

self.addEventListener('push', ... );

(A menos que hayas jugado con los trabajadores web antes, es probable que self sea nuevo. En un archivo de service worker, self hace referencia al propio service worker).

Cuando se reciba un mensaje push, se llamará al objeto de escucha de eventos y crearás una notificación llamando a showNotification() en la propiedad registration del service worker. showNotification() requiere title. También puedes asignarle un objeto options para configurar un mensaje, un ícono y una insignia en el cuerpo. (La insignia solo se usa en Android al momento de redactar este documento).

const title = 'Push Codelab';
const options = {
  body: 'Yay it works.',
  icon: 'images/icon.png',
  badge: 'images/badge.png'
};
self.registration.showNotification(title, options);

Lo último que debes abarcar en el control de eventos de push es event.waitUntil(). Este método requiere una promesa para permitir que el navegador mantenga el service worker activo y en ejecución hasta que se resuelva la promesa que se pasó.

Para que el código anterior sea un poco más fácil de entender, puedes volver a escribirlo de la siguiente manera:

const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);

Ahora que ya recorriste el evento push, probemos un evento push.

Probar

Con el manejo de eventos push en el service worker, puedes activar un evento push falso para probar lo que sucede cuando se recibe un mensaje.

En tu app web, suscríbete a los mensajes push y asegúrate de ver User IS subscribed en la consola. En el panel Application en Herramientas para desarrolladores, en la pestaña Service Workers, haz clic en el botón Push:

1ee499267eeccd1c.png

Después de hacer clic en Push, deberías ver una notificación como la siguiente:

379105dfb0ea56d8.png

Nota: Si este paso no funciona, intenta anular el registro del service worker con el vínculo Unregister del panel de la app de Herramientas para desarrolladores, espera a que se detenga el service worker y vuelve a cargar la página.

8. Clic en notificaciones

Código completo

Si haces clic en una de estas notificaciones, notarás que no sucede nada. Para controlar los clics de notificación, puedes escuchar los eventos notificationclick en tu service worker.

Para comenzar, agrega un objeto de escucha notificationclick en sw.js:

self.addEventListener('notificationclick', function(event) {
  console.log('[Service Worker] Notification click received.');

  event.notification.close();

  event.waitUntil(
    clients.openWindow('https://developers.google.com/web')
  );
});

Cuando el usuario haga clic en la notificación, se llamará al objeto de escucha de eventos notificationclick.

El código primero cierra la notificación en la que se hizo clic:

event.notification.close();

Luego, se abre una ventana o pestaña nueva que carga la URL https://developers.google.com/web. Puedes cambiar esto si lo deseas.

event.waitUntil(
    clients.openWindow('https://developers.google.com/web/')
  );

event.waitUntil() garantiza que el navegador no finalice el service worker antes de que se muestre la ventana o pestaña nueva.

Probar

Vuelve a intentar activar un mensaje push en Herramientas para desarrolladores y haz clic en la notificación. Verás que se cierra la notificación y se abre una pestaña nueva.

9. Envía mensajes push

Viste que tu app web puede mostrar una notificación con Herramientas para desarrolladores y viste cómo cerrar la notificación con un clic. El siguiente paso es enviar un mensaje push real.

Normalmente, esto requeriría el envío de una suscripción desde una página web a un backend. Entonces, el backend activaría un mensaje push realizando una llamada a la API hacia el extremo de la suscripción.

Esto está fuera del alcance de este codelab, pero puedes usar el sitio complementario ( web-push-codelab.glitch.me) para activar un mensaje push real. Pega la suscripción en la parte inferior de la página:

bb202867962a0249.png

Luego, pega esto en el sitio complementario, en el área de texto de Suscripción a Enviar a:

a0dd93bc33a9e8cf.png

En Texto para enviar, agrega cualquier cadena que desees enviar con el mensaje push.

Haz clic en el botón Enviar mensaje push.

a5e8e89411ec034.png

Deberías recibir un mensaje de envío. El texto que usaste se registrará en la consola.

f6815a356d4f9aaa.png

Esto debería darte la oportunidad de probar el envío y la recepción de datos, y de manipular notificaciones como resultado.

La aplicación complementaria es simplemente un servidor de nodo que usa la biblioteca web-push para enviar mensajes. Te recomendamos revisar la organización web-push-libs en GitHub para ver qué bibliotecas están disponibles para enviar mensajes push por ti. Esto controla muchos de los detalles para activar los mensajes de envío.

Puede ver todo el código del sitio complementario aquí.

10. Anula la suscripción del usuario

Código completo

Lo único que falta es la capacidad de anular la suscripción de un usuario a push. Para ello, debes llamar a unsubscribe() en un PushSubscription.

En tu archivo scripts/main.js, cambia el objeto de escucha de clics pushButton en initializeUI() a lo siguiente:

pushButton.addEventListener('click', function() {
  pushButton.disabled = true;
  if (isSubscribed) {
    unsubscribeUser();
  } else {
    subscribeUser();
  }
});

Ten en cuenta que ahora llamarás a una nueva función unsubscribeUser(). En esta función, obtendrás la suscripción actual y llamarás a unsubscribe() en ella. Agrega el siguiente código a scripts/main.js:

function unsubscribeUser() {
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    if (subscription) {
      return subscription.unsubscribe();
    }
  })
  .catch(function(error) {
    console.log('Error unsubscribing', error);
  })
  .then(function() {
    updateSubscriptionOnServer(null);

    console.log('User is unsubscribed.');
    isSubscribed = false;

    updateBtn();
  });
}

Analicemos esta función.

Primero, llama a getSubscription() para obtener la suscripción actual:

swRegistration.pushManager.getSubscription()

Se mostrará una promesa que se resuelve con un PushSubscription, si existe. De lo contrario, muestra null. Si hay una suscripción, llamarás a unsubscribe() en ella, lo que hará que el PushSubscription no sea válido.

swRegistration.pushManager.getSubscription()
.then(function(subscription) {
  if (subscription) {
    // TODO: Tell application server to delete subscription
    return subscription.unsubscribe();
  }
})
.catch(function(error) {
  console.log('Error unsubscribing', error);
})

Llamar a unsubscribe() muestra una promesa, ya que puede tardar un tiempo en completarse. Muestras esa promesa para que el siguiente then() de la cadena espere a que unsubscribe() finalice. También debes agregar un controlador de captura en caso de que llamar a unsubscribe() genere un error. Luego, puedes actualizar tu IU.

.then(function() {
  updateSubscriptionOnServer(null);

  console.log('User is unsubscribed.');
  isSubscribed = false;

  updateBtn();
})

Probar

Deberías poder presionar Enable Push Messaging o Disable Push Messaging en tu aplicación web, y los registros mostrarán que el usuario está suscrito y anulado la suscripción.

81a07119235b53da.png

11. Finalizado

¡Felicitaciones por completar este codelab!

En este codelab, te mostramos cómo comenzar a agregar notificaciones push a tu app web. Si quieres obtener más información sobre lo que pueden hacer las notificaciones web, consulta estos documentos.

Si deseas implementar notificaciones de aplicación en tu sitio, puede que te interese agregar compatibilidad con navegadores más antiguos o navegadores que no cumplen con los estándares y que usan GCM. Obtén más información aquí.

Lecturas adicionales

Entradas de blog relevantes