Como o JavaScript funciona: a mecânica das notificações por push na Web
Este é o post #9 da série dedicada a explorar JavaScript e seus componentes de construção. No processo de identificação e descrição dos elementos centrais, também compartilhamos algumas regras práticas que usamos ao criar o SessionStack , um aplicativo JavaScript leve que precisa ser robusto e altamente eficiente para ajudar os usuários a ver e reproduzir seus defeitos de aplicativos da Web em tempo real. .
Abaixo estão os posts dessa série publicados até o momento
- Uma visão geral do mecanismo, o tempo de execução e a pilha de chamadas
- Dentro do motor V8 do Google + 5 dicas sobre como escrever código otimizado
- Gerenciamento de memória + como lidar com 4 vazamentos comuns de memória
- O Event loop e o surgimento da programação assíncrona + 5 maneiras de codificar melhor com async/await
- Como o JavaScript funciona: Aprofundando em WebSockets e HTTP/2 com SSE + como escolher o caminho certo
- Como funciona o JavaScript: uma comparação com o WebAssembly + por quê, em certos casos, é melhor usá-lo sobre JavaScript
- Como o JavaScript funciona: Os blocos de construção dos Web Workers + 5 casos quando você deve usá-los
Hoje voltamos nossa atenção para notificações por push da Web: veremos os componentes de construção, exploraremos os processos por trás do envio/recebimento de notificações e, no final, compartilharemos como planejamos usá -los para criar uma nova funcionalidade do produto.
As notificações por push são muito comuns no mundo dos dispositivos móveis. Por um motivo ou outro, eles fizeram sua entrada na web muito tarde, embora tenha sido um recurso altamente solicitado pelos desenvolvedores.
Visão geral
As notificações por push da Web permitem que os usuários optem por atualizações oportunas de aplicativos da web que visam engajar novamente a base de usuários com conteúdo que pode ser interessante, importante e oportuno para os usuários.
O push é baseado em Service Workers, que discutimos em detalhes em um post anterior .
A razão para empregar trabalhadores do serviço, neste caso, é porque eles operam em segundo plano. Isso é ótimo para notificações push porque significa que o código está sendo executado apenas quando um usuário interage com a notificação em si.
Push & notificação
Push e notificação são duas APIs diferentes.
- Push — é invocado quando o servidor fornece informações a um Service Worker.
- Notificação — esta é a ação de um Service Worker ou um script em um aplicativo da web que mostra informações para o usuário.
Push (Empurrar)
Existem três etapas gerais para implementar um push:
- A interface do usuário — adicionando a lógica do lado do cliente necessária para inscrever um usuário em um push. Essa é a lógica JavaScript de que a interface do seu aplicativo da web precisa para permitir que o usuário se registre para enviar mensagens.
- Enviando a mensagem push — implementando a chamada da API no seu servidor que aciona uma mensagem push para o dispositivo do usuário.
- Recebendo a mensagem de envio — manipulando a mensagem de envio quando ela chega no navegador.
Agora vamos descrever todo o processo em mais detalhes.
Detecção de suporte ao navegador
Primeiro, precisamos verificar se o navegador atual suporta envio de mensagens. Podemos verificar se o push é suportado por duas verificações simples:
- Verificar
serviceWorker
no objeto donavigator
- Verifique o
PushManager
no objeto dawindow
Ambas as verificações são assim:
Registrar um Service Worker
Neste ponto, sabemos que o recurso é suportado. O próximo passo é registrar nosso Service Worker.
Registrar um Service Worker é algo com o qual você já deve estar familiarizado em uma postagem anterior da nossa.
Solicitando permissão
Depois que um Service Worker for registrado, poderemos continuar assinando o usuário. Para fazer isso, precisamos obter permissão para enviar mensagens de push.
A API para obter permissão é relativamente simples, mas a desvantagem é que a API mudou de um retorno de chamada para um Promise . Isso apresenta um problema: não podemos dizer qual versão da API foi implementada pelo navegador atual, então você precisa implementar e manipular ambos.
Parece algo como isto:
A chamada Notification.requestPermission()
exibirá o seguinte aviso para o usuário:
Quando a permissão for concedida, fechada ou bloqueada, receberemos o resultado como uma string: 'granted'
, 'default'
ou 'denied'
.
Lembre-se de que, se o usuário clicar no botão Block
, seu aplicativo da Web não poderá solicitar permissão ao usuário até que ele "desbloqueie" o aplicativo manualmente alterando o estado da permissão. Esta opção está enterrada no painel de configurações.
Inscrevendo um usuário no PushManager
Assim que tivermos o nosso Service Worker registrado e tivermos permissão, podemos inscrever um usuário chamando registration.pushManager.subscribe()
quando você registrar seu Service Worker.
O snippet inteiro pode ter esta aparência (incluindo o registro do Service Worker):
O registration.pushManager.subscribe(options)
usa um objeto de opções , que consiste em parâmetros obrigatórios e opcionais:
- userVisibleOnly : Um booleano que indica que a assinatura de push retornada será usada apenas para mensagens cujo efeito é tornado visível para o usuário. Tem que ser definido para
true
caso contrário, você receberá um erro (há razões históricas para isso). - applicationServerKey : Um
DOMString
ouArrayBuffer
codificado em Base64 contendo uma chave pública que o servidor de envio utilizará para autenticar seu servidor de aplicativos.
Seu servidor precisa gerar um par de chaves do servidor de aplicativos — elas também são conhecidas como chaves VAPID, exclusivas do servidor. Eles são um par de chave pública e privada. A chave privada é secretamente armazenada no seu final, enquanto a pública é trocada com o cliente. As chaves permitem que um serviço de envio saiba qual servidor de aplicativos assinou um usuário e garante que ele seja o mesmo servidor que aciona as mensagens de envio para esse usuário específico.
Você precisa criar o par de chaves privada/pública apenas uma vez para o seu aplicativo. Uma maneira de fazer isso é https://web-push-codelab.glitch.me/ .
O navegador passa o applicationServerKey
(o public) para um serviço de push ao inscrever o usuário, o que significa que o serviço de push pode vincular a chave pública do seu aplicativo ao PushSubscription
do usuário.
Isto é o que acontece:
- Seu aplicativo da web é carregado e você chama
subscribe()
, passando sua chave de servidor. - O navegador faz uma solicitação de rede a um serviço de push que gerará um nó de extremidade, associará esse nó de extremidade à chave e retornará o nó de extremidade ao navegador.
- O navegador adicionará esse terminal ao objeto
PushSubscription
, que é retornado por meio da promessasubscribe()
.
Posteriormente, sempre que você quiser enviar uma mensagem push, será necessário criar um cabeçalho de autorização que contenha informações assinadas com a chave privada do seu servidor de aplicativos. Quando o serviço push recebe uma solicitação para enviar uma mensagem push, ele validará o cabeçalho procurando a chave pública que já está vinculada a esse endpoint específico (a segunda etapa).
O objeto PushSubscription
Um PushSubscription
contém todas as informações necessárias para enviar uma mensagem push para o dispositivo do usuário. É assim que parece:
{
"endpoint": "https://domain.pushservice.com/some-id",
"keys": {
"p256dh": "BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=",
"auth":"FPssMOQPmLmXWmdSTdbKVw=="
}
}
O endpoint
é o URL dos serviços push. Para acionar uma mensagem push, faça uma solicitação POST para esse URL.
O objeto de keys
contém os valores usados para criptografar os dados da mensagem enviados com uma mensagem push.
Depois que um usuário é inscrito e você tem um PushSubscription
é necessário enviá-lo ao seu servidor. Lá (no servidor) você salvará a assinatura em um banco de dados e a partir de agora a usará para enviar mensagens push para esse usuário.
Enviando a mensagem push
Quando você quiser enviar uma mensagem push para seus usuários, a primeira coisa que você precisa é de um serviço push. Você está dizendo ao serviço de push (via chamada de API) quais dados enviar, quem enviar a mensagem e quais os critérios sobre como enviar a mensagem. Normalmente, essa chamada da API é feita no seu servidor.
Serviços push
Um serviço push é aquele que recebe solicitações, valida-as e envia a mensagem push para o navegador adequado.
Observe que o serviço push não é gerenciado por você — é um serviço de terceiros. Seu servidor é aquele que se comunica com o serviço push por meio de uma API. Um exemplo de serviço de envio é o FCM do Google .
O serviço de push lida com todo o trabalho pesado. Por exemplo, se o navegador estiver off-line, o serviço de push colocará as mensagens na fila e aguardará até que o navegador fique on-line novamente, antes de enviar a respectiva mensagem.
Cada navegador pode usar qualquer serviço de push desejado e isso é algo que está além do controle do desenvolvedor.
Todos os serviços push, no entanto, possuem as mesmas APIs, portanto, isso não cria dificuldades de implementação.
Para obter a URL que manipulará as solicitações para suas mensagens push, você precisará verificar o valor armazenado do endpoint
no objeto PushSubscription
.
API de serviço push
O Push Service API fornece uma maneira de enviar mensagens para um usuário. A API é o Web Push Protocol, que é um padrão IETF que define como você faz uma chamada de API para um serviço de push.
Os dados que você envia com uma mensagem push devem ser criptografados. Dessa forma, você evita que os serviços de push possam exibir os dados enviados. Isso é importante porque o navegador é aquele que decide qual serviço de envio usar (e pode estar usando algum serviço de envio não confiável e não seguro o suficiente).
Para cada mensagem de envio, você também pode fornecer as seguintes instruções:
- TTL — define por quanto tempo uma mensagem deve ser enfileirada antes de ser removida e não entregue.
- Prioridade — define a prioridade de cada mensagem, que permite que o serviço de envio envie apenas as de alta prioridade, caso a duração da bateria do dispositivo do usuário tenha que ser preservada.
- Tópico — fornece uma mensagem push a um nome de tópico que substituirá mensagens pendentes com o mesmo tópico, para que, quando o dispositivo estiver ativo, o usuário não receba informações desatualizadas.
Empurrar evento no navegador
Depois de enviar a mensagem para o serviço de push, conforme explicado acima, a mensagem estará em um estado pendente até que uma das seguintes situações aconteça:
- O dispositivo fica online.
- A mensagem expira na fila devido ao TTL.
Quando o serviço de envio envia uma mensagem, o navegador irá recebê-lo, descriptografá-lo e despachar um evento push
em seu Service Worker.
O melhor de tudo é que o navegador pode executar seu Service Worker mesmo quando sua página da web não estiver aberta. O seguinte acontece:
- A mensagem push chega ao navegador, que descriptografa
- O navegador acorda o trabalhador de serviço
- Um evento
push
é enviado para o Service Worker
O código para configurar um ouvinte de evento de envio deve ser bem parecido com qualquer outro ouvinte de evento que você escreveria em JavaScript:
Uma das coisas a se entender sobre os Trabalhadores do Serviço é que você tem pouco controle sobre o tempo que o código do service worker será executado. O navegador decide quando acordá-lo e quando finalizá-lo.
Em Service Workers, event.waitUntil(promise)
informa ao navegador que o trabalho está em andamento até que a promessa seja resolvida e ele não deve finalizar o service worker se desejar que o trabalho seja concluído.
Aqui está um exemplo de como manipular o evento push
:
Chamar self.registration.showNotification()
exibe uma notificação para o usuário e retorna uma promessa que será resolvida assim que a notificação for exibida.
O showNotification(title, options)
pode ser visualmente ajustado para atender às suas necessidades. O parâmetro title
é uma string
enquanto options é um objeto assim:
{
"//": "Visual Options",
"body": "<String>",
"icon": "<URL String>",
"image": "<URL String>",
"badge": "<URL String>",
"vibrate": "<Array of Integers>",
"sound": "<URL String>",
"dir": "<String of 'auto' | 'ltr' | 'rtl'>",
"//": "Behavioural Options",
"tag": "<String>",
"data": "<Anything>",
"requireInteraction": "<boolean>",
"renotify": "<Boolean>",
"silent": "<Boolean>",
"//": "Both Visual & Behavioural Options",
"actions": "<Array of Strings>",
"//": "Information Option. No visual affect.",
"timestamp": "<Long>"
}
Você pode ler com mais detalhes o que cada opção faz aqui — https://developer.mozilla.org/pt-BR/docs/Web/API/ServiceWorkerRegistration/showNotification .
As notificações por push podem ser uma ótima maneira de chamar a atenção dos usuários sempre que houver informações urgentes, importantes e urgentes que você queira compartilhar com elas.
Nós da SessionStack, por exemplo, planejamos utilizar notificações push para informar nossos usuários quando houver uma falha, problema ou anomalia em seus produtos. Isso permitirá que nossos usuários saibam imediatamente que há algo errado acontecendo. Em seguida, eles podem reproduzir o problema como um vídeo e ver tudo o que aconteceu com o usuário final aproveitando os dados coletados por nossa biblioteca, como alterações do DOM, interações do usuário, solicitações de rede, exceções não tratadas e mensagens de depuração.
Esse recurso não apenas ajudará nossos usuários a entender e reproduzir qualquer problema, mas também permitirá que os clientes sejam alertados assim que isso acontecer.
Existe um plano gratuito se você quiser experimentar o SessionStack .
Referências
- https://developers.google.com/web/fundamentals/push-notifications/
- https://developers.google.com/web/fundamentals/push-notifications/how-push-works
- https://developers.google.com/web/fundamentals/push-notifications/subscribing-a-user
- https://developers.google.com/web/fundamentals/push-notifications/handling-messages
Este é um artigo traduzido com a autorização do autor. O artigo original pode ser lido em https://blog.sessionstack.com/how-javascript-works-the-mechanics-of-web-push-notifications-290176c5c55d
Autor do post original — Alexander Zlatkov — Co-founder & CEO @SessionStack