Notificações push na Web aberta

Se você perguntar a vários desenvolvedores quais recursos de dispositivos móveis estão faltando na Web, as notificações push estarão sempre no topo da lista.

As notificações push permitem que os usuários ativem as atualizações dos sites que eles adoram receber em tempo hábil e que você engaje-os novamente com conteúdo personalizado e envolvente.

A partir do Chrome 42, a API Push e a API Notification estão disponíveis para desenvolvedores.

A API Push no Chrome depende de algumas tecnologias diferentes, incluindo Manifestos de apps da Web e Service Workers. Nesta postagem, analisaremos cada uma dessas tecnologias, mas apenas o mínimo para começar a usar as mensagens push. Para entender melhor alguns dos outros recursos dos manifestos e dos recursos off-line dos service workers, confira os links acima.

Também veremos o que será adicionado à API em versões futuras do Chrome e, por fim, teremos as perguntas frequentes.

Implementar mensagens push para o Chrome

Esta seção descreve cada etapa que você precisa concluir para oferecer suporte a mensagens push no seu app da Web.

Registrar um Service Worker

É necessário ter um service worker para implementar mensagens push para a Web. O motivo é que, quando uma mensagem push é recebida, o navegador pode iniciar um service worker, que é executado em segundo plano, sem que uma página esteja aberta, e despachar um evento para que você possa decidir como lidar com essa mensagem push.

Veja abaixo um exemplo de como registrar um service worker no seu app da Web. Quando o registro for concluído, chamamos initialiseState(), que abordaremos em 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.');
    }
});

O gerenciador de cliques do botão inscreve ou cancela a inscrição do usuário em mensagens push. isPushEnabled é uma variável global que simplesmente rastreia se as mensagens push estão inscritas no momento ou não. Elas serão usadas em todos os snippets de código.

Em seguida, verificamos se há suporte para service workers antes de registrar o arquivo service-worker.js, que tem a lógica para processar uma mensagem push. Estamos simplesmente informando ao navegador que esse arquivo JavaScript é o service worker do nosso site.

Configurar o estado inicial

Exemplo de UX de mensagens push ativada e desativada no Chrome.

Depois que o service worker é registrado, precisamos configurar o estado da nossa interface.

Os usuários esperam uma interface simples para ativar ou desativar mensagens push do seu site e esperam que ela se mantenha atualizada com todas as alterações que ocorrerem. Em outras palavras, se ele ativar as mensagens push para seu site, sair e voltar uma semana depois, sua interface deverá destacar que as mensagens push já estão ativadas.

Veja algumas diretrizes de UX neste documento. Nele, vamos nos concentrar nos aspectos técnicos.

Neste momento, você pode estar pensando que há apenas dois estados para lidar: ativado ou desativado. No entanto, há alguns outros estados relacionados às notificações que você precisa considerar.

Um diagrama destacando as diferentes considerações e o estado do push no Chrome

Há várias APIs que precisamos verificar antes de ativar nosso botão. Se tudo for compatível, será possível ativar nossa interface e definir o estado inicial para indicar se as mensagens push estão inscritas ou não.

Como a maioria dessas verificações resulta na desativação da nossa interface, defina o estado inicial como desativado. Isso também evita qualquer confusão caso haja um problema com o JavaScript da página, por exemplo, não seja possível fazer o download do arquivo JS ou o usuário tenha desativado o JavaScript.

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

Com esse estado inicial, podemos realizar as verificações descritas acima no método initialiseState(), ou seja, depois que nosso service worker é registrado.

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

Uma breve visão geral dessas etapas:

  • Verificamos se showNotification está disponível no protótipo ServiceWorkerRegistration. Sem ela, não será possível mostrar uma notificação do nosso service worker quando uma mensagem push for recebida.
  • Verificamos qual é o Notification.permission atual para garantir que ele não seja "denied". Uma permissão negada significa que não é possível mostrar notificações até que o usuário mude manualmente a permissão no navegador.
  • Para saber se as mensagens push são compatíveis, confira se PushManager está disponível no objeto da janela.
  • Por fim, usamos pushManager.getSubscription() para verificar se já temos uma assinatura. Se isso acontecer, vamos enviar os detalhes da assinatura ao nosso servidor para garantir que temos as informações corretas e definir nossa interface para indicar que as mensagens push já estão ativadas ou não. Vamos conferir quais detalhes existem no objeto de assinatura mais adiante neste artigo.

Aguardamos até que navigator.serviceWorker.ready seja resolvido para verificar se há uma assinatura e ativar o botão push, porque só depois que o service worker estiver ativo é que você pode se inscrever para receber mensagens de push.

A próxima etapa é processar quando o usuário quer ativar mensagens push. No entanto, antes de fazer isso, precisamos configurar um projeto do Google Play Console e adicionar alguns parâmetros ao nosso manifesto para usar o Firebase Cloud Messaging (FCM), anteriormente conhecido como Google Cloud Messaging (GCM).

Criar um projeto no Firebase Developer Console

O Chrome usa o FCM para gerenciar o envio e a entrega de mensagens push. No entanto, para usar a API FCM, é necessário configurar um projeto no Firebase Developer Console.

As etapas a seguir são específicas para o navegador Chrome, Opera para Android e Samsung que usam o FCM. Discutiremos como isso funciona em outros navegadores posteriormente neste artigo.

Criar um novo projeto de desenvolvedor do Firebase

Para começar, é preciso criar um novo projeto em https://console.firebase.google.com/, clicando em "Criar novo projeto".

Captura de tela do novo projeto do Firebase

Adicione um nome e crie o projeto, e você será direcionado ao painel dele:

Página inicial do projeto do Firebase

Neste painel, clique na engrenagem ao lado do nome do projeto no canto superior esquerdo e clique em "Configurações do projeto".

Menu de configurações do projeto do Firebase

Na página de configurações, clique na guia "Cloud Messaging".

Menu do Cloud Messaging do projeto do Firebase

Esta página contém a chave de API para mensagens push, que será usada mais tarde, e o ID do remetente, que precisamos colocar no manifesto do app da Web na próxima seção.

Adicionar um manifesto de app da Web

Para push, precisamos adicionar um arquivo de manifesto com um campo gcm_sender_id para que a assinatura de push funcione. Esse parâmetro só é exigido pelo Chrome, Opera para Android e navegador Samsung para que possam usar o FCM / GCM.

O gcm_sender_id é usado por esses navegadores ao inscrever um dispositivo de usuários com o FCM. Isso significa que o FCM pode identificar o dispositivo do usuário e garantir que o ID do remetente corresponda à chave de API correspondente e que o usuário tenha permitido que o servidor envie mensagens push.

Confira abaixo um arquivo de manifesto bem simples:

{
    "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>"
}

Defina o valor gcm_sender_id como o ID do remetente do seu projeto do Firebase.

Depois de salvar o arquivo de manifesto no projeto (manifest.json é um bom nome), faça referência a ele no HTML com a seguinte tag no cabeçalho da sua página.

<link rel="manifest" href="/manifest.json">

Se não adicionar um manifesto da Web com esses parâmetros, você receberá uma exceção ao tentar inscrever o usuário para enviar mensagens de push, com o erro "Registration failed - no sender id provided" ou "Registration failed - permission denied".

Inscrever-se em mensagens push

Agora que você configurou um manifesto, pode voltar ao JavaScript dos seus sites.

Para se inscrever, é preciso chamar o método subscribe() no objeto PushManager, que pode ser acessado pelo ServiceWorkerRegistration.

Isso vai solicitar que o usuário conceda permissão à origem para enviar notificações push. Sem essa permissão, você não poderá se inscrever.

Se a promessa retornada pelo método subscribe() for resolvida, você receberá um objeto PushSubscription que vai conter um endpoint.

O endpoint precisa ser salvo no seu servidor para cada usuário, já que você precisará dele para enviar mensagens push mais tarde.

O código a seguir inscreve o usuário para mensagens 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';
        }
        });
    });
}

Neste ponto, seu app da Web está pronto para receber uma mensagem de push. No entanto, nada acontecerá até que um listener de eventos de push seja adicionado ao nosso arquivo do service worker.

Listener de eventos de push do Service Worker

Quando uma mensagem push é recebida (falaremos sobre como enviá-la na próxima seção), um evento push será despachado no service worker. Nesse ponto, será necessário exibir uma notificação.

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

Esse código registra um listener de eventos push e mostra uma notificação com um título, texto, ícone e tag de notificação predefinidos. Uma sutileza a ser destacada com este exemplo é o método event.waitUntil(). Esse método recebe uma promessa e estende o ciclo de vida de um manipulador de eventos (ou pode ser considerado como mantendo o service worker ativo) até que a promessa seja definida. Nesse caso, a promessa passada para event.waitUntil é a promessa retornada de showNotification().

A tag de notificação atua como um identificador para notificações exclusivas. Se enviarmos duas mensagens push para o mesmo endpoint com um pequeno atraso entre elas e exibirmos notificações com a mesma tag, o navegador exibirá a primeira notificação e a substituirá pela segunda quando ela for recebida.

Para mostrar várias notificações de uma vez, use uma tag diferente ou nenhuma tag. Vamos conferir um exemplo mais completo de como mostrar uma notificação mais adiante nesta postagem. Por enquanto, vamos simplificar e conferir se enviar uma mensagem push mostra essa notificação.

Como enviar uma mensagem push

Nós nos inscrevemos para receber mensagens push, e nosso service worker está pronto para mostrar uma notificação, então é hora de enviar uma mensagem push pelo FCM.

Isso se aplica apenas aos navegadores que usam o FCM.

Quando você envia a variável PushSubscription.endpoint ao seu servidor, o endpoint do FCM é especial. Ele tem um parâmetro no final do URL, que é um registration_id.

Um exemplo de endpoint seria:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

O URL do FCM é:

https://fcm.googleapis.com/fcm/send

O registration_id seria:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

Isso é específico para navegadores que usam o FCM. Em um navegador normal, você simplesmente teria um endpoint e chamaria esse endpoint de maneira padrão, e isso funcionaria independentemente do URL.

Isso significa que, no seu servidor, você precisará verificar se o endpoint é para o FCM e, em caso afirmativo, extrair o register_id. Para fazer isso em Python, use algo como:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

Quando você tiver o ID de registro, poderá fazer uma chamada para a API FCM. Confira os documentos de referência sobre a API FCM.

Os principais aspectos a serem lembrados ao chamar o FCM são:

  • Um cabeçalho Authorization com um valor de key=&lt;YOUR_API_KEY&gt; precisa ser definido quando você chama a API, em que &lt;YOUR_API_KEY&gt; é a chave de API do projeto do Firebase.
    • A chave de API é usada pelo FCM para encontrar o ID do remetente adequado, garantir que o usuário tenha concedido permissão ao projeto e, por fim, garantir que o endereço IP do servidor esteja na lista de permissões para esse projeto.
  • Um cabeçalho Content-Type apropriado de application/json ou application/x-www-form-urlencoded;charset=UTF-8, dependendo de você enviar os dados como JSON ou dados de formulário.
  • Uma matriz de registration_ids, que são os IDs de registro extraídos dos endpoints dos usuários.

Consulte os documentos sobre como enviar mensagens de push do seu servidor, mas para uma verificação rápida do seu service worker, use o cURL para enviar uma mensagem push ao seu navegador.

Troque &lt;YOUR_API_KEY&gt; e &lt;YOUR_REGISTRATION_ID&gt; nesse comando cURL pelos seus e execute-os em um terminal.

Você verá uma notificação incrível:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Exemplo de uma mensagem push do Chrome para Android.

Ao desenvolver a lógica de back-end, lembre-se de que o cabeçalho de autorização e o formato do corpo POST são específicos para o endpoint do FCM. Portanto, detecte quando o endpoint é para o FCM e adicione condicionalmente o cabeçalho e formate o corpo POST. Para outros navegadores (e o Chrome no futuro), será necessário implementar o Web Push Protocol.

Uma desvantagem da implementação atual da API Push no Chrome é que você não pode enviar dados com uma mensagem push. Nada. O motivo disso é que, em uma implementação futura, os dados de payload terão que ser criptografados no seu servidor antes de serem enviados para um endpoint de mensagens push. Dessa forma, seja qual for o provedor de push, o endpoint não visualizará facilmente o conteúdo da mensagem push. Isso também protege contra outras vulnerabilidades, como validação ruim de certificados HTTPS e ataques "man-in-the-middle" entre o servidor e o provedor de push. No entanto, essa criptografia ainda não é compatível. Enquanto isso, você precisará realizar uma busca para conseguir as informações necessárias para preencher uma notificação.

Um exemplo mais completo de evento de push

A notificação que vimos até agora é bastante básica e, no que diz respeito às amostras, não é suficiente para abranger um caso de uso real.

Na realidade, a maioria das pessoas quer receber algumas informações do servidor antes de exibir a notificação. Isso pode ser dados para preencher o título e a mensagem da notificação com algo específico ou ir além e armazenar em cache algumas páginas ou dados para que, quando o usuário clicar na notificação, tudo fique imediatamente disponível quando o navegador for aberto, mesmo que a rede não esteja disponível naquele momento.

No código a seguir, buscamos alguns dados de uma API, convertemos a resposta em um objeto e o usamos para preencher nossa notificação.

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

Mais uma vez, vale a pena destacar que o event.waitUntil() usa uma promessa que resulta na promessa retornada por showNotification(). Isso significa que nosso listener de eventos não será encerrado até que a chamada fetch() assíncrona seja concluída e a notificação seja mostrada.

Você vai perceber que mostramos uma notificação mesmo quando há um erro. Isso porque, se não fizermos isso, o Chrome mostrará sua própria notificação genérica.

Abrir um URL quando o usuário clica em uma notificação

Quando o usuário clica em uma notificação, um evento notificationclick é enviado no service worker. Dentro do gerenciador, você pode realizar a ação apropriada, como focar uma guia ou abrir uma janela com um URL específico:

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

Este exemplo abre o navegador na raiz da origem do site, focando em uma guia de mesma origem, se houver, e abrindo uma nova.

Há uma postagem dedicada a algumas das coisas que você pode fazer com a API Notification (em inglês).

Cancelar inscrição no dispositivo de um usuário

Você se inscreveu no dispositivo de um usuário, e ele está recebendo mensagens push. Mas como cancelar a inscrição?

As principais etapas necessárias para cancelar a inscrição de um dispositivo de usuário é chamar o método unsubscribe() no objeto PushSubscription e remover o endpoint dos servidores para que você não envie mensagens push que já sabe que não serão recebidas. O código abaixo faz exatamente isso:

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

Como manter a assinatura atualizada

As assinaturas podem ficar fora de sincronia entre o FCM e seu servidor. Verifique se o servidor analisa o corpo da resposta do POST de envio da API FCM, procurando pelos resultados error:NotRegistered e canonical_id, conforme explicado na documentação do FCM.

As assinaturas também podem ficar fora de sincronia entre o service worker e o servidor. Por exemplo, depois de assinar/cancelar a inscrição, uma conexão de rede fragmentada pode impedir que você atualize o servidor, ou um usuário pode revogar a permissão de notificações, o que aciona um cancelamento automático. Gerencie esses casos verificando o resultado de serviceWorkerRegistration.pushManager.getSubscription() periodicamente (por exemplo, no carregamento de página) e sincronizando-o com o servidor. Você também pode se inscrever de novo automaticamente se não tiver mais uma assinatura e Notification.permission == 'granted'.

Em sendSubscriptionToServer(), você terá que considerar como processar solicitações de rede com falha ao atualizar o endpoint. Uma solução é rastrear o estado da endpoint em um cookie para determinar se o servidor precisa dos detalhes mais recentes ou não.

Todas as etapas acima resultam em uma implementação completa de mensagens push na Web no Chrome 46. Ainda há recursos específicos que tornarão as coisas mais fáceis (como uma API padrão para acionar mensagens push), mas esta versão permite que você comece a criar mensagens push em seus aplicativos da Web hoje mesmo.

Como depurar seu app da Web

Ao implementar mensagens de push, os bugs ficarão em um destes dois locais: sua página ou seu service worker.

Os bugs da página podem ser depurados usando o DevTools. Para depurar problemas de service worker, você tem duas opções:

  1. Acesse chrome://inspect > Service Workers. Essa visualização não fornece muitas informações além dos service workers em execução no momento.
  2. Acesse chrome://serviceworker-internals para ver o estado dos service workers e verificar erros, se houver algum. Esta página é temporária até que o DevTools tenha um conjunto de recursos semelhante.

Uma das melhores dicas que posso dar a qualquer pessoa que não tenha experiência com service workers é usar a caixa de seleção "Abrir janela do DevTools e pausar a execução do JavaScript na inicialização do service worker para depuração". Essa caixa de seleção adicionará um ponto de interrupção no início do service worker e pausa a execução. Isso permite retomar ou percorrer o script do service worker e ver se você encontrou algum problema.

Captura de tela mostrando onde a caixa de seleção &quot;Pausar execução&quot; está em serviceworker-internals.

Se houver um problema entre o FCM e o evento push do seu service worker, não há muito o que fazer para depurar o problema, já que não há como você verificar se o Chrome recebeu algo. O mais importante é garantir que a resposta do FCM seja bem-sucedida quando o servidor fizer uma chamada de API. Ela terá esta aparência:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

Observe a resposta "success": 1. Se, em vez disso, você vir uma falha, isso sugere que há algo de errado com o ID de registro do FCM e que a mensagem de push não está sendo enviada ao Chrome.

Depuração de service workers no Google Chrome para Android

No momento, a depuração de service workers no Google Chrome para Android não é óbvia. Acesse chrome://inspect, encontre o dispositivo e procure um item de lista com o nome "Worker pid:...." que tenha o URL do seu service worker.

Captura de tela mostrando onde os service workers ficam na inspeção do Chrome

UX para notificações push

A equipe do Chrome está montando um documento de práticas recomendadas para UX de notificações push, bem como um documento que aborda alguns dos casos extremos ao trabalhar com notificações push.

O futuro das mensagens push no Chrome e na Web aberta

Esta seção entra em detalhes sobre algumas das partes específicas do Chrome dessa implementação que você precisa conhecer e como ela será diferente de outras implementações de navegador.

Protocolo de push da Web e endpoints

A beleza do padrão da API Push é que você pode pegar o endpoint, transmiti-lo ao servidor e enviar mensagens push implementando o protocolo de push da Web.

O protocolo de push da Web é um novo padrão que os provedores de push podem implementar, permitindo que os desenvolvedores não precisem se preocupar com quem é o provedor de push. A ideia é evitar a necessidade de se inscrever para chaves de API e enviar dados especialmente formatados, como você tem que fazer com o FCM.

O Chrome foi o primeiro navegador a implementar a API Push, e o FCM não oferece suporte ao protocolo Web Push. Por esse motivo, o Chrome exige a gcm_sender_id e você precisa usar a API RESTful para o FCM.

O objetivo final do Chrome é adotar o Web Push Protocol com o Chrome e o FCM.

Até lá, você precisa detectar o endpoint "https://fcm.googleapis.com/fcm/send" e processá-lo separadamente de outros endpoints, ou seja, formatar os dados de payload de uma maneira específica e adicionar a chave de autorização.

Como implementar o protocolo de push na Web?

O Firefox Nightly está atualmente trabalhando no push e provavelmente será o primeiro navegador a implementar o Web Push Protocol.

Perguntas frequentes

Onde estão as especificações?

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ (link em inglês) https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

Posso evitar notificações duplicadas se minha presença na Web tiver várias origens ou se eu tiver uma presença nativa e na Web?

Não há uma solução para isso no momento, mas você pode acompanhar o progresso no Chromium.

O cenário ideal seria ter algum tipo de ID para o dispositivo de um usuário e, no lado do servidor, corresponder os IDs de assinatura do app nativo e da Web e decidir para qual deles enviar uma mensagem push. Você pode fazer isso pelo tamanho da tela, modelo do dispositivo, compartilhando uma chave gerada entre o app da Web e o app nativo, mas cada abordagem tem prós e contras.

Por que preciso de um gcm_sender_id?

Isso é necessário para que o Chrome, o Opera para Android e o navegador Samsung possam usar a API Firebase Cloud Messaging (FCM). A meta é usar o protocolo de push da Web quando o padrão estiver finalizado e o FCM puder oferecer suporte a ele.

Por que não usar soquetes da Web ou eventos enviados pelo servidor (EventSource)?

A vantagem de usar mensagens push é que, mesmo que a página esteja fechada, o service worker será ativado e poderá mostrar uma notificação. Os soquetes da Web e o EventSource têm a conexão encerrada quando a página ou o navegador é fechado.

E se eu não precisar da entrega de eventos em segundo plano?

Se você não precisa de entrega em segundo plano, os Web Sockets são uma ótima opção.

Quando posso usar o recurso "Push" sem mostrar notificações (por exemplo, com o envio silencioso em segundo plano)?

Ainda não há um cronograma de quando isso estará disponível, mas há uma intent para implementar a sincronização em segundo plano. Embora isso não seja decidido nem especificado, há discussão sobre a ativação do envio silencioso com sincronização em segundo plano.

Por que requer HTTPS? Como posso contornar isso durante o desenvolvimento?

Os service workers exigem origens seguras para garantir que o script do service worker seja da origem pretendida e não seja de um ataque "man-in-the-middle". Atualmente, isso significa usar HTTPS em sites ativos, embora o host local funcione durante o desenvolvimento.

Como é a compatibilidade com navegadores?

O Chrome é compatível em sua versão estável e o Mozilla está trabalhando no Firefox Nightly. Consulte o bug Como implementar a API Push para mais informações, e você pode acompanhar a implementação da notificação aqui.

Posso remover uma notificação depois de um determinado período?

No momento, isso não é possível, mas estamos planejando adicionar suporte para mostrar uma lista das notificações visíveis no momento. Se você tiver um caso de uso para definir uma expiração para a notificação depois que ela for criada, gostaríamos de saber o que é. Adicione um comentário e nós a encaminharemos para a equipe do Chrome.

Se você só precisa impedir que uma notificação push seja enviada ao usuário após um determinado período e não se importar por quanto tempo a notificação permanece visível, use o parâmetro time to live (ttl) do FCM neste link.

Quais são as limitações das mensagens push no Chrome?

Há algumas limitações descritas nesta postagem:

  • O uso do CCM pelo Chrome como um serviço de push cria vários requisitos próprios. Estamos trabalhando juntos para ver se algumas delas podem ser removidas no futuro.
  • Você precisa mostrar uma notificação ao receber uma mensagem push.
  • O Chrome para computador tem a ressalva de que, se ele não estiver em execução, as mensagens push não serão recebidas. Isso é diferente do ChromeOS e do Android, em que as mensagens push são sempre recebidas.

Não deveríamos usar a API Permissions?

A API Permission é implementada no Chrome, mas não necessariamente estará disponível em todos os navegadores. Saiba mais neste link.

Por que o Chrome não abre a guia anterior quando clico em uma notificação?

Esse problema afeta apenas páginas que não são controladas atualmente por um service worker. Saiba mais nesta postagem.

E se uma notificação estiver desatualizada no momento em que o dispositivo do usuário recebeu o push?

Sempre é necessário mostrar uma notificação ao receber uma mensagem push. Se você quiser enviar uma notificação, mas ela só for útil por um determinado período, será possível usar o parâmetro "time_to_live" no CCM para que o FCM não envie a mensagem push caso passe do tempo de expiração.

Confira mais detalhes aqui.

O que acontece se eu enviar 10 mensagens push, mas quiser que o dispositivo receba apenas uma?

O FCM tem um parâmetro "collection_key" que pode ser usado para instruí-lo a substituir qualquer mensagem pendente que tenha o mesmo "crescer_key" pela nova mensagem.

Confira mais detalhes aqui.