Adicionar notificações push a um app da Web

1. Visão geral

As mensagens push são uma maneira simples e eficaz de reengajar seus usuários. Neste codelab, você aprenderá a adicionar notificações push ao seu app da Web.

O que você vai aprender

  • Como inscrever e cancelar a inscrição de um usuário em mensagens push
  • Como lidar com mensagens push recebidas
  • Como exibir uma notificação
  • Como responder a cliques de notificação

O que é necessário

  • Chrome 52 ou superior
  • Servidor da Web para Chrome ou o servidor da Web de sua preferência
  • Um editor de texto
  • Conhecimento básico de HTML, CSS, JavaScript e Chrome DevTools
  • O exemplo de código (consulte "Como configurar")

2. Começar a configuração

Fazer o download do exemplo de código

Há duas maneiras de acessar o exemplo de código para este codelab:

  • Clone o repositório Git:
git clone https://github.com/GoogleChrome/push-notifications.git
  • Faça o download do arquivo ZIP:

Se você fizer o download da origem como um arquivo ZIP, a descompactação terá uma pasta raiz push-notifications-master.

Instalar e verificar o servidor da Web

Embora você seja livre para usar seu próprio servidor da Web, este codelab foi projetado para funcionar bem com o app Servidor da Web para Chrome. Se você ainda não tiver esse app instalado, faça o download na Chrome Web Store:

Após instalar o app do servidor da Web para Chrome, clique no atalho Apps na barra de favoritos:

946bcaaad66e5c8e.png

Na janela "Apps", clique no ícone do servidor da Web:

9f3c21b2cf6cbfb5.png

Você verá esta caixa de diálogo, que permite configurar seu servidor da Web local:

73543edeb27c3d6f.png

Clique no botão Choose folder e selecione a pasta app na pasta push-notifications que você transferiu por download. Isso permite exibir o trabalho em andamento pelo URL mostrado na seção URLs do servidor da Web da caixa de diálogo.

Em Opções, marque a caixa ao lado de Mostrar index.html automaticamente, conforme mostrado abaixo:

5ac11bca86ce7369.png

Em seguida, interrompa e reinicie o servidor deslizando o controle Web Server: STARTED para a esquerda e depois de volta para a direita.

d42f87972f9fec24.png

Clique no URL do servidor da Web para visitar seu site no navegador. Você verá uma página semelhante a esta, embora sua versão possa mostrar 127.0.0.1:8887 como o endereço:

00-push-codelab.png

Sempre atualize o service worker

Durante o desenvolvimento, é útil garantir que o service worker esteja sempre atualizado e tenha as alterações mais recentes.

Para fazer essa configuração no Chrome:

  1. Acesse a guia Push Codelab.
  2. Abra o DevTools: Ctrl-Shift-I no Windows e no Linux, Cmd-Option-I no macOS.
  3. Selecione o painel Application, clique na guia Service Workers e marque a caixa de seleção Update on Reload. Quando essa caixa de seleção está marcada, o service worker é forçosamente atualizado sempre que a página é recarregada.

e7d384fb77885b99.png

3. Registrar um service worker

Código concluído

No diretório app, há um arquivo vazio chamado sw.js. Esse arquivo será seu service worker. Por enquanto, ele pode ficar vazio. Você adicionará um código a ele mais tarde.

Primeiro, você precisa registrar esse arquivo como seu service worker.

Sua página do app/index.html carrega scripts/main.js. Registre o service worker nesse arquivo JavaScript.

Adicione o código a seguir 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';
}

Esse código verifica se o seu navegador oferece suporte aos service workers e às mensagens push. Se eles forem compatíveis, o código registrará seu arquivo sw.js.

Fazer um teste

Para verificar as alterações, atualize a guia Push Codelab no navegador.

Verifique se há um Service Worker is registered message no console do Chrome DevTools, desta forma:

5d7ad383d6f235d5.png

Receber chaves do servidor de aplicativos

Para trabalhar com este codelab, você precisa gerar chaves de servidor de aplicativos. Você pode fazer isso no site complementar: web-push-codelab.glitch.me (link em inglês)

Aqui é possível gerar um par de chaves pública e privada.

push-codelab-04-companion.png

Copie sua chave pública para scripts/main.js, substituindo o valor <Your Public Key>:

const applicationServerPublicKey = '<Your Public Key>';

Importante: nunca coloque a chave privada em um app da Web.

4. Estado de inicialização

Código concluído

No momento, o botão Ativar do app da Web está desativado e não pode ser clicado. Isso ocorre porque é uma boa prática desativar o botão push por padrão e ativá-lo depois que você souber que o navegador aceita mensagens push e conseguir verificar se o usuário está inscrito ou não para enviar mensagens.

Você precisará criar duas funções em scripts/main.js:

  • initializeUI, para verificar se o usuário está inscrito no momento.
  • updateBtn, para ativar o botão e mudar o texto dependendo da inscrição do usuário ou não.

Adicione uma função initializeUI a main.js desta forma:

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

O novo método usa a swRegistration da etapa anterior, recebe a propriedade pushManager e chama getSubscription() nela.

pushManager: getSubscription() retorna uma promessa que é resolvida com a assinatura atual, se houver uma. Caso contrário, retorna null. Com isso, é possível verificar se o usuário já está inscrito, definir o valor de isSubscribed e chamar updateBtn() para atualizar o botão.

Adicione a função updateBtn() a main.js:

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

  pushButton.disabled = false;
}

Esta função ativa o botão e altera o texto do botão dependendo se o usuário está inscrito ou não.

A última coisa a fazer é chamar initializeUI() quando o service worker estiver registrado em main.js:

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

  swRegistration = swReg;
  initializeUI();
})

Fazer um teste

Atualize a guia Push Codelab. Você verá que o botão Enable Push Messaging agora está ativado (é possível clicar nele) e você deve ver User is NOT subscribed no console.

a1553f4a0483d227.png

À medida que você avança neste codelab, o texto do botão vai mudar sempre que você se inscrever ou cancelar a inscrição.

5. Fazer a inscrição do usuário

Código concluído

No momento, o botão Ativar mensagens push não tem muita utilidade. Vamos corrigir isso.

Na função initializeUI(), adicione um listener de clique para o botão:

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

Quando o usuário clica no botão, você o desativa apenas para garantir que ele não possa clicar nele uma segunda vez, pois a inscrição em mensagens push pode levar algum tempo.

Em seguida, chame subscribeUser() se o usuário não estiver inscrito no momento. Para isso, cole o seguinte código no 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();
  });
}

Vamos analisar o que esse código está fazendo e como ele está inscrevendo o usuário para mensagens push.

Primeiro, converta a chave pública do servidor do aplicativo, que é codificada em Base64 segura para URL, em UInt8Array, porque essa é a entrada esperada da chamada subscribe(). A função urlB64ToUint8Array() está na parte de cima do scripts/main.js.

Depois de converter o valor, chame o método subscribe() no pushManager do service worker, transmitindo a chave pública do servidor do aplicativo e o valor userVisibleOnly: true.

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

O parâmetro userVisibleOnly garante que você vai mostrar uma notificação sempre que uma mensagem push for enviada. Atualmente, esse valor é obrigatório e precisa ser verdadeiro.

Chamar subscribe() retorna uma promessa que será resolvida após as seguintes etapas:

  1. O usuário concedeu permissão para mostrar notificações.
  2. O navegador enviou uma solicitação de rede a um serviço de push para receber os dados necessários e gerar um PushSubscription.

A promessa subscribe() vai ser resolvida com PushSubscription se essas etapas forem concluídas. Se o usuário não conceder a permissão ou se houver algum problema para inscrever o usuário, a promessa será rejeitada com um erro. Isso fornece a seguinte cadeia de promessa no 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();
});

Com isso, você recebe uma assinatura e trata o usuário como inscrito ou pega um erro e o registra no console. Em ambos os cenários, chame updateBtn() para garantir que o botão seja reativado e tenha o texto adequado.

Em um aplicativo real, a função updateSubscriptionOnServer() é para onde você enviaria os dados da sua assinatura para um back-end. No entanto, para o codelab, você apenas exibe a assinatura na sua interface. Adicione a seguinte função 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');
  }
}

Fazer um teste

Acesse a guia Push Codelab, atualize a página e clique no botão. Será exibida uma solicitação de permissão como esta:

fcc61267a0194e81.png

Se você conceder a permissão, verá User is subscribed registrado no console. O texto do botão mudará para Desativar mensagens push e você poderá ver a assinatura como dados JSON na parte inferior da página.

5c5505f2ead037c.png

6. Permissão de gerenciamento negada

Código concluído

Uma coisa que você ainda não tratou é o que acontece se o usuário bloquear a solicitação de permissão. Isso precisa de uma consideração exclusiva porque, se o usuário bloquear a permissão, seu app da Web não poderá mostrar novamente a solicitação de permissão e não poderá inscrever o usuário. Você precisa desativar pelo menos o botão de push para que o usuário saiba que ele não pode ser usado.

O lugar óbvio para lidar com esse cenário é na função updateBtn(). Tudo o que você precisa fazer é verificar o valor Notification.permission da seguinte forma:

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

Se a permissão for denied, o usuário não poderá se inscrever e não haverá mais nada que você possa fazer. Por isso, desativar permanentemente o botão é a melhor abordagem.

Fazer um teste

Como você já deu permissão ao seu app da Web na etapa anterior, é necessário clicar em i em um círculo na barra de URL e mudar a permissão Notificações para Usar padrão global (Perguntar).

54495592074f10ae.png

Depois de alterar essa configuração, atualize a página e clique no botão Ativar mensagens push e selecione Bloquear na caixa de diálogo de permissão. O botão será desativado e mostrará o texto Push Messaging Bloqueado.

d4cf22468f6defda.png

Com essa alteração, agora é possível inscrever o usuário, considerando os possíveis cenários de permissão.

7. Processar um evento push

Código concluído

Antes de aprender a enviar uma mensagem push do back-end, você precisa considerar o que realmente vai acontecer quando um usuário inscrito receber uma mensagem push.

Quando você aciona uma mensagem push, o navegador recebe a mensagem push, descobre para qual service worker o envio se destina, ativa esse service worker e despacha um evento push. Você precisa ouvir esse evento e mostrar uma notificação como resultado.

Adicione o seguinte código ao arquivo 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));
});

Vamos analisar este código. Para detectar eventos push no service worker, adicione um listener de eventos:

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

A menos que você já tenha jogado com Web Workers, o self provavelmente é novo. Em um arquivo de service worker, self faz referência ao próprio service worker.

Quando uma mensagem push é recebida, o listener de eventos é chamado, e você cria uma notificação chamando showNotification() na propriedade registration do service worker. showNotification() requer um title; Você também pode usar um objeto options para definir o corpo da mensagem, um ícone e um selo. No momento, o selo é usado apenas em dispositivos Android.

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

A última coisa a ser abordada no processamento de eventos push é event.waitUntil(). Esse método usa uma promessa para permitir que o navegador mantenha seu service worker ativo e em execução até que a promessa transmitida seja resolvida.

Para tornar o código acima um pouco mais fácil de entender, você pode reescrever assim:

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

Agora que você já analisou o evento push, vamos testar um evento push.

Fazer um teste

Com o gerenciamento de eventos de push no service worker, é possível acionar um evento push falso para testar o que acontece quando uma mensagem é recebida.

No seu app da Web, inscreva-se para receber mensagens push e verifique se você vê User IS subscribed no console. No painel Application do DevTools, na guia Service Workers, clique no botão Push:

1eeccd1c.png

Depois de clicar em Enviar, você verá uma notificação como esta:

379105dfb0ea56d8.png

Observação: se esta etapa não funcionar, tente cancelar o registro do seu service worker com o link Unregister no painel DevTools Application, aguarde o service worker ser parado e, em seguida, recarregue a página.

8. Clique em notificação

Código concluído

Se você clicar em uma dessas notificações, perceberá que nada acontece. Para processar cliques em notificações, detecte eventos notificationclick no service worker.

Comece adicionando um listener notificationclick em 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')
  );
});

Quando o usuário clicar na notificação, o listener de eventos notificationclick será chamado.

O código primeiro fecha a notificação que foi clicada:

event.notification.close();

Em seguida, uma nova janela ou guia será aberta, carregando o URL https://developers.google.com/web. Sinta-se à vontade para alterar isso.

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

event.waitUntil() garante que o navegador não encerre o service worker antes que a nova janela ou guia seja exibida.

Fazer um teste

Tente acionar uma mensagem push no DevTools novamente e clique na notificação. Agora você verá a notificação fechar e uma nova guia ser aberta.

9. Enviar mensagens push

Você viu que seu app da Web é capaz de mostrar uma notificação usando o DevTools e aprendeu a fechar a notificação com um clique. A próxima etapa é enviar uma mensagem push real.

Normalmente, isso exigiria o envio de uma assinatura de uma página da Web para um back-end. O back-end acionaria então uma mensagem push fazendo uma chamada de API para o endpoint na assinatura.

Isso está fora do escopo deste codelab, mas é possível usar o site complementar ( web-push-codelab.glitch.me) para acionar uma mensagem push real. Cole a inscrição na parte inferior da sua página:

bb202867962a0249.png

Em seguida, cole-o no site complementar na área de texto Subscription to Send To:

a0dd93bc33a9e8cf.png

Em Texto para enviar, adicione qualquer string que você queira enviar com a mensagem push.

Clique no botão Enviar mensagem push.

a5e8e89411ec034.png

Em seguida, você deve receber uma mensagem push. O texto usado será registrado no console.

f6815a356d4f9aaa.png

Isso deve lhe dar uma chance de testar o envio e recebimento de dados e a manipular as notificações como resultado.

O app complementar é apenas um servidor de nó que usa a biblioteca de push da Web para enviar mensagens. Consulte a organização web-push-libs no GitHub para ver quais bibliotecas estão disponíveis para enviar mensagens push para você. Isso lida com muitos detalhes para acionar mensagens push.

Veja todo o código para o site complementar aqui.

10. Cancelar a inscrição do usuário

Código concluído

A única coisa que está faltando é a capacidade de cancelar a inscrição de um usuário por push. Para fazer isso, é necessário chamar unsubscribe() em uma PushSubscription.

No arquivo scripts/main.js, mude o listener de clique pushButton em initializeUI() para o seguinte:

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

Agora você vai chamar uma nova função unsubscribeUser(). Nessa função, você recebe a assinatura atual e chama unsubscribe() nela. Adicione o código a seguir à 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();
  });
}

Vamos conhecer essa função.

Primeiro, você recebe a assinatura atual chamando getSubscription():

swRegistration.pushManager.getSubscription()

Isso retorna uma promessa que é resolvida com uma PushSubscription, se houver uma. Caso contrário, ele retornará null. Se houver uma assinatura, chame unsubscribe() nela, o que torna o PushSubscription invá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);
})

Chamar unsubscribe() retorna uma promessa, já que pode levar algum tempo para ser concluído. Você retorna essa promessa para que o próximo then() na cadeia aguarde a conclusão do unsubscribe(). Você também adiciona um gerenciador de captura caso chamar unsubscribe() resulte em um erro. Depois disso, você pode atualizar a interface.

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

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

  updateBtn();
})

Fazer um teste

Você deve conseguir pressionar Ativar mensagens push ou Desativar mensagens push no seu app da Web, e os registros mostrarão o usuário sendo inscrito e cancelado.

81a07119235b53da.png

11. Concluído

Parabéns por concluir este codelab.

Este codelab mostrou como começar a usar a adição de notificações push ao seu app da Web. Para saber mais sobre o que as notificações da Web podem fazer, consulte estes documentos.

Se você quiser implantar notificações push em seu site, talvez esteja interessado em adicionar suporte para navegadores mais antigos ou navegadores não compatíveis com os padrões que usam o GCM. Saiba mais aqui.

Leia mais

Postagens do blog relevantes