Notificações push na Web aberta

Se você perguntar a uma sala de 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 o recebimento de atualizações em tempo hábil nos sites que eles adoram e permitem que você os envolva novamente com conteúdo personalizado e envolvente.

A partir da versão 42 do Chrome, a API Push e 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 ativar as mensagens push. Para entender melhor alguns dos outros recursos de manifestos e os recursos off-line dos service workers, confira os links acima.

Também veremos o que será adicionado à API em futuras versões do Chrome e, por fim, teremos uma seção de Perguntas frequentes.

Como implementar mensagens push para o Chrome

Nesta seção, descrevemos cada etapa que você precisa concluir para dar suporte a mensagens push no seu app da Web.

Registrar um service worker

Há uma dependência de 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ê decida como processar 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 para enviar mensagens de push. isPushEnabled é uma variável global que simplesmente rastreia se as mensagens de push estão inscritas no momento ou não. Eles serão referenciados em todos os snippets de código.

Em seguida, verificamos se os service workers são compatíveis antes de registrar o arquivo service-worker.js, que tem a lógica para processar uma mensagem push. Aqui, 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 for registrado, precisamos configurar o estado da interface.

Os usuários esperam que uma interface simples ative ou desative as mensagens push no seu site e que ela se mantenha atualizada com as alterações que ocorrerem. Em outras palavras, se elas ativam mensagens push para seu site, saem e retornam uma semana depois, a interface precisa destacar que as mensagens push já estão ativadas.

Veja algumas diretrizes de UX neste documento. Neste artigo, nos concentraremos nos aspectos técnicos.

Neste ponto, talvez você esteja pensando que há apenas dois estados com que lidar: ativado ou desativado. No entanto, existem alguns outros estados relacionados às notificações que você precisa considerar.

Diagrama destacando as diferentes considerações e o estado do envio por push no Chrome

Há várias APIs que precisamos verificar antes de ativar nosso botão. Se tudo tiver suporte, podemos ativar a 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 interface, você precisa definir 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 é possível fazer o download do arquivo JS ou o usuário desativou o JavaScript).

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

Com esse estado inicial, é possível realizar as verificações descritas acima no método initialiseState(), ou seja, depois que o 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 podemos mostrar uma notificação do nosso service worker quando uma mensagem push é recebida.
  • Verificamos qual é o Notification.permission atual para garantir que ele não é "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 verificar se mensagens push há suporte, confira se PushManager está disponível no objeto da janela.
  • Por fim, usamos pushManager.getSubscription() para verificar se já temos uma assinatura ou não. Se isso acontecer, vamos enviar os detalhes da assinatura ao nosso servidor para garantir que temos as informações corretas e configurar a IU para indicar que as mensagens push já estão ativadas ou não. Mais adiante neste artigo, veremos quais detalhes existem no objeto de assinatura.

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

A próxima etapa é gerenciar 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 Play Console

O Chrome usa o FCM para processar o envio e a entrega de mensagens push. No entanto, para usar a API FCM, você precisa configurar um projeto no Console para desenvolvedores do Firebase.

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

Criar um novo projeto de desenvolvedor do Firebase

Para começar, crie 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. Você vai acessar o painel do projeto:

Página inicial do projeto do Firebase

Nesse 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 projeto na nuvem do Firebase

Esta página contém a chave de API para mensagens push, que usaremos posteriormente, 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, é necessário adicionar um arquivo de manifesto com um campo gcm_sender_id para que a assinatura de push tenha êxito. Esse parâmetro só é exigido pelos navegadores Chrome, Opera para Android e Samsung para que eles 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 verificar se o código do remetente corresponde à chave de API correspondente e se o usuário permitiu que o servidor envie mensagens push.

Confira abaixo um arquivo de manifesto super 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 seu 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 você não adicionar um manifesto da Web com esses parâmetros, vai receber uma exceção ao tentar inscrever o usuário para enviar mensagens push com o erro "Registration failed - no sender id provided" ou "Registration failed - permission denied".

Inscrever-se nas mensagens push

Agora que o manifesto foi configurado, você pode voltar para o JavaScript do seu site.

Para se inscrever, é necessário chamar o método subscribe() no objeto PushManager, que você acessa por meio do 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 conterá um endpoint.

O endpoint precisa ser salvo no seu servidor para cada usuário, já que vai ser necessário que eles enviem 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';
        }
        });
    });
}

Nesse ponto, seu app da Web está pronto para receber uma mensagem push, mas nada acontecerá até que adicionarmos um listener de eventos de push ao arquivo do nosso service worker.

Listener de eventos push do service worker

Quando uma mensagem push for recebida (falaremos sobre como enviar uma mensagem de push na próxima seção), um evento de push será enviado no service worker. Nesse ponto, você precisará 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 uma tag de notificação predefinidos. Uma sutileza a ser destacada neste 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 transmitida para event.waitUntil é a promessa retornada de showNotification().

A tag de notificação funciona como um identificador de 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, substituindo-a pela segunda quando a mensagem for recebida.

Se você quiser mostrar várias notificações de uma vez, use uma tag diferente ou nenhuma tag. Vamos analisar um exemplo mais completo de exibição de uma notificação mais adiante nesta postagem. Por enquanto, vamos simplificar e ver se o envio de uma mensagem push mostra essa notificação.

Como enviar uma mensagem push

Fizemos a inscrição 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 só é aplicável aos navegadores que usam o FCM.

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

Este é um exemplo de endpoint:

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 tem um endpoint e o chama de maneira padrão, e ele funciona independentemente do URL.

Isso significa que, no seu servidor, você precisará verificar se o endpoint é para o FCM e, se for, extrair o register_id. Para fazer isso em Python, você pode fazer 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'

Assim que tiver o código de registro, você poderá fazer uma chamada para a API FCM. Veja documentos de referência sobre a API FCM aqui.

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 do projeto do Firebase.
    • A chave de API é usada pelo FCM para encontrar o ID do remetente apropriado, verificar se o usuário deu permissão para o projeto e, por fim, garantir que o endereço IP do servidor esteja na lista de permissões do projeto.
  • Um cabeçalho Content-Type apropriado de application/json ou application/x-www-form-urlencoded;charset=UTF-8, dependendo se você envia os dados como JSON ou de formulário.
  • Uma matriz de registration_ids. Esses são os IDs de registro que você extrairá dos endpoints dos seus usuários.

Confira os documentos (em inglês) sobre como enviar mensagens push do servidor. No entanto, para uma verificação rápida do service worker, use cURL (em inglês) para enviar uma mensagem push ao navegador.

Troque o &lt;YOUR_API_KEY&gt; e o &lt;YOUR_REGISTRATION_ID&gt; neste comando cURL pelos seus e o execute em um terminal.

Uma notificação gloriosa será exibida:

    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 sua lógica de back-end, lembre-se de que o cabeçalho e o formato de autorização do corpo do POST são específicos para o endpoint do FCM. Portanto, detecte quando o endpoint for para o FCM e adicione condicionalmente o cabeçalho e formate o corpo do POST. Para outros navegadores (e esperamos que seja o Chrome no futuro), será necessário implementar o protocolo de push da Web.

Uma desvantagem da implementação atual da API Push no Chrome é que não é possível enviar dados com uma mensagem push. Não, nada. Isso porque, em uma implementação futura, os dados de payload precisarão ser criptografados no seu servidor antes de serem enviados para um endpoint de mensagens push. Dessa forma, o endpoint, seja qual for o provedor de push, não poderá visualizar facilmente o conteúdo da mensagem push. Isso também protege contra outras vulnerabilidades, como validação incorreta 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, é necessário executar uma busca para receber as informações necessárias para preencher uma notificação.

Um exemplo de evento push mais completo

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

Na verdade, a maioria das pessoas quer receber algumas informações do servidor antes de mostrar a notificação. Podem ser dados para preencher o título e a mensagem da notificação com algo específico, ou ir além e armazenar algumas páginas ou dados em cache 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 a 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() recebe uma promessa que resulta na promessa retornada por showNotification(), o que significa que nosso listener de eventos não será encerrado até que a chamada assíncrona fetch() seja concluída e a notificação seja exibida.

Nós mostramos uma notificação mesmo quando há um erro. Isso ocorre porque, se não fizermos isso, o Chrome mostrará a 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. No gerenciador, você pode realizar a ação adequada, 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 existir, e abrindo uma nova.

Há uma postagem dedicada a algumas das coisas que você pode fazer com a API Notification aqui.

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

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

Para cancelar a inscrição no dispositivo de um usuário, as principais etapas necessárias são chamar o método unsubscribe() no objeto PushSubscription e remover o endpoint dos seus servidores para não enviar mensagens push que você 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 inscrições podem ficar fora de sincronia entre o FCM e o servidor. Verifique se o servidor analisa o corpo da resposta de POST de envio da API FCM, procurando 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 fazer/cancelar a inscrição com sucesso, uma conexão de rede instável pode impedir que você atualize seu servidor ou um usuário pode revogar a permissão de notificações, o que aciona um cancelamento automático de cancelamento da inscrição. Para lidar com esses casos, verifique o resultado de serviceWorkerRegistration.pushManager.getSubscription() periodicamente (por exemplo, no carregamento de página) e sincronize-o com o servidor. Você também pode querer refazer a assinatura automaticamente se não tiver mais uma assinatura e Notification.permission == 'granted'.

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

Todas as etapas acima resultam em uma implementação completa de mensagens push na Web no Chrome 46. Ainda há recursos com especificações 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 nos seus aplicativos da Web hoje mesmo.

Como depurar seu app da Web

Ao implementar mensagens push, os bugs ficam em um destes dois lugares: sua página ou o service worker.

Os bugs na página podem ser depurados usando o DevTools. Para depurar problemas do service worker, há 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 e, daqui, você pode visualizar o estado dos service workers e ver os erros, se houver. Essa página é temporária até que o DevTools tenha um conjunto de recursos semelhante.

Uma das melhores dicas que posso dar a quem é novo em service workers é usar a caixa de seleção chamada "Abrir a janela do DevTools e pausar a execução do JavaScript na inicialização do service worker para depuração". Essa caixa de seleção vai adicionar um ponto de interrupção no início do service worker e pausar 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 de pausa da execução está no serviceworker-internals.

Se parece haver um problema entre o FCM e o evento push do service worker, não há muito que você possa fazer para depurar o problema, já que não há como ver 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. Ele será algo assim:

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

Observe a resposta "success": 1. Se, em vez disso, uma falha for exibida, isso sugere que algo não está certo com o código de registro do FCM e que a mensagem de push não está sendo enviada ao Chrome.

Como depurar service workers no Chrome para Android

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

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

UX para notificações push

A equipe do Chrome está elaborando um documento de práticas recomendadas para a UX de notificações push e também um documento que abrange 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 dessa implementação do Chrome 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 acessar o endpoint, transmiti-lo ao seu servidor e enviar mensagens de push implementando o protocolo de push da Web.

O Web Push Protocol é um novo padrão que os provedores de push podem implementar, permitindo que os desenvolvedores não precisem se preocupar com o provedor de push. A ideia é que isso evita a necessidade de se inscrever para chaves de API e enviar dados especialmente formatados, como acontece com o FCM.

O Chrome foi o primeiro navegador a implementar a API Push, e o FCM não oferece suporte ao Web Push Protocol, e é por isso que o Chrome exige o gcm_sender_id e você precisa usar a API RESTful para o FCM.

O objetivo do Chrome é começar a usar o protocolo de push da Web com o Chrome e o FCM.

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

Como implementar o protocolo de push da Web?

O Firefox Nightly está atualmente trabalhando em 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/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/ (link em inglês)

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 existe 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, em seguida, no lado do servidor, fazer a correspondência dos IDs de assinatura do app nativo e do app da Web e decidir para qual deles enviar uma mensagem push. Você poderia fazer isso pelo tamanho da tela, pelo 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). O objetivo é 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 Web Sockets ou Eventos enviados pelo servidor (EventSource)?

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

E se eu não precisar do envio de eventos em segundo plano?

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

Quando posso usar a opção "push" sem mostrar notificações (por exemplo, notificações push silenciosas em segundo plano)?

Não há um cronograma para quando isso vai estar disponível ainda, mas há uma intent de implementar a sincronização em segundo plano e, embora isso não esteja decidido ou especificado, há algumas discussões sobre a ativação de envio silencioso com sincronização em segundo plano.

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

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

Como é o suporte ao navegador?

O Chrome oferece suporte à sua versão estável e o Mozilla tem push no Firefox Nightly. Consulte o bug sobre como implementar a API Push para mais informações e acompanhe a implementação de notificações aqui.

Posso remover uma notificação após um determinado período?

No momento, isso não é possível, mas estamos planejando adicionar suporte para receber 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 é. Por isso, adicione um comentário e o encaminharemos para a equipe do Chrome.

Se você precisar interromper o envio de uma notificação push 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, saiba mais aqui.

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

Existem algumas limitações descritas nesta postagem:

  • O uso do CCM pelo Chrome como um serviço de push cria vários requisitos reservados. Estamos trabalhando juntos para ver se algumas delas podem ser suspensas no futuro.
  • Você precisa mostrar uma notificação quando recebe 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. Esse recurso é diferente do ChromeOS e do Android, em que as mensagens push sempre são recebidas.

Não devemos usar a API Permissions?

A API Permission está implementada no Chrome, mas não estará necessariamente 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 as páginas que não são controladas no momento 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?

Você sempre precisa mostrar uma notificação ao receber uma mensagem push. Caso você queira enviar uma notificação, mas ela seja útil apenas durante um determinado período, use o parâmetro "time_to_live" no CCM para que o FCM não envie a mensagem push se ela expirar.

Confira mais detalhes aqui.

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

O FCM tem um parâmetro "recolhimento" que pode ser usado para que ele substitua as mensagens pendentes que tenham a mesma chave reduzida pela nova mensagem.

Confira mais detalhes aqui.