Notificações push na Web aberta

Se você perguntar a um grupo de desenvolvedores quais recursos importantes os dispositivos móveis têm a mais que a Web, as notificações por push estão sempre no topo da lista.

As notificações push permitem que os usuários aceitem atualizações oportunas dos sites que eles adoram e que você envolva os usuários novamente com eficácia, usando conteúdo personalizado e envolvente.

A partir da versão 42 do Chrome, a API Push e a API Notifications 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. Neste post, vamos analisar cada uma dessas tecnologias, mas apenas o mínimo necessário para colocar as mensagens push em funcionamento. 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 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. Isso acontece porque, 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 enviar um evento para que você possa decidir como processar essa mensagem push.

Confira abaixo um exemplo de como registrar um worker de serviço no seu app da Web. Quando o registro for concluído, vamos chamar initialiseState(), que será abordado 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. Eles serão referenciados em todos os snippets de código.

Em seguida, verificamos se os service workers têm suporte 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 este arquivo JavaScript é o service worker do nosso site.

Configurar o estado inicial

Exemplo de UX de mensagens push ativadas e desativadas no Chrome.

Depois que o service worker for registrado, vamos configurar o estado da 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 eles ativarem as mensagens push no seu site, saírem e voltarem uma semana depois, a interface vai destacar que as mensagens push já estão ativadas.

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

Nesse ponto, você pode estar pensando que há apenas dois estados para lidar, ativado ou desativado. No entanto, há outros estados relacionados a 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 o botão. Se tudo tiver suporte, podemos ativar a interface e definir o estado inicial para indicar se a mensagem push está ativada ou não.

Como a maioria dessas verificações resulta na desativação da 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 o service worker for 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 você não pode mostrar notificações até que o usuário mude manualmente a permissão no navegador.
  • Para verificar se há suporte a mensagens push, verificamos se PushManager está disponível no objeto de janela.
  • Por fim, usamos pushManager.getSubscription() para verificar se já temos uma assinatura. Se sim, enviamos os detalhes da assinatura para nosso servidor para garantir que temos as informações corretas e definir nossa interface para indicar se as mensagens push já estão ativadas ou não. Vamos analisar 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 processar o envio e a entrega de mensagens push. No entanto, para usar a API FCM, você precisa configurar um projeto no console do desenvolvedor do Firebase.

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 para desenvolvedores do Firebase

Para começar, clique em "Criar novo projeto" em https://console.firebase.google.com/.

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

Nesse painel, clique no ícone de engrenagem ao lado do nome do projeto no canto superior esquerdo e em "Configurações do projeto".

Menu de configurações do projeto do Firebase

Na página de configurações, clique na guia "Mensagens na nuvem".

Menu do Firebase Project Cloud Messaging

Esta página contém a chave de API para mensagens push, que vamos usar 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 inscrição push seja bem-sucedida. Esse parâmetro é necessário apenas pelo Chrome, Opera para Android e Samsung Browser para que eles possam usar o FCM/GCM.

O gcm_sender_id é usado por esses navegadores quando ele inscreve um dispositivo do usuário no 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 notificações push.

Confira abaixo um arquivo de manifesto supersimples:

{
    "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 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 em mensagens push, com o erro "Registration failed - no sender id provided" ou "Registration failed - permission denied".

Inscrever-se nas 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 pedir que o usuário conceda permissão à origem para enviar notificações push. Sem essa permissão, não será possível fazer a assinatura.

Se a promessa retornada pelo método subscribe() for resolvida, você vai receber um objeto PushSubscription que 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 evento push e exibe uma notificação com um título, texto do corpo, ícone e uma tag de notificação predefinidos. Uma sutileza a destacar neste exemplo é o método event.waitUntil(). Esse método recebe uma promessa e estende a duração de um gerenciador de eventos (ou pode ser considerado como manter o service worker ativo), até que a promessa seja resolvida. Neste caso, a promessa transmitida para event.waitUntil é a promessa retornada de showNotification().

A tag de notificação funciona 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

Assinamos as mensagens push, e nosso service worker está pronto para mostrar uma notificaçã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.

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

Isso significa que no servidor, você precisa verificar se o endpoint é para o FCM e, se for, extrair o registration_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'

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 apropriado, garantir que o usuário tenha concedido permissão para o 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 adequado de application/json ou application/x-www-form-urlencoded;charset=UTF-8, dependendo se você envia os dados como JSON ou dados de formulário.
  • Uma matriz de registration_ids: são os IDs de registro que você extrairia dos endpoints dos usuários.

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

Troque &lt;YOUR_API_KEY&gt; e &lt;YOUR_REGISTRATION_ID&gt; neste comando cURL por seus próprios valores e execute-o 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 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 do POST são específicos do endpoint do FCM. Portanto, detecte quando o endpoint é para o FCM e adicione condicionalmente o cabeçalho e formate o corpo do POST. Para outros navegadores (e, esperamos, 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 você não pode enviar dados com uma mensagem push. Não, 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, o endpoint, seja qual for o provedor de push, não poderá acessar facilmente o conteúdo da mensagem push. Isso também protege contra outras vulnerabilidades, como a validação inadequada de certificados HTTPS e ataques do tipo "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.

Exemplo de evento push mais completo

A notificação que vimos até agora é bem básica e, em relação a amostras, não é muito boa para cobrir um caso de uso do mundo real.

Na realidade, a maioria das pessoas vai querer 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 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 abaixo, 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
        });
    })
    );
});

Vale ressaltar, mais uma vez, que o event.waitUntil() usa uma promessa que resulta na promessa retornada por showNotification(), o que significa que nosso listener de eventos não vai sair até que a chamada fetch() assíncrona seja concluída e a notificação seja mostrada.

Você vai notar que mostramos uma notificação mesmo quando há um erro. Isso acontece porque, se não fizermos isso, o Chrome vai 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 seu manipulador, é possível 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 uma guia de mesma origem, se houver uma, ou abrindo uma nova.

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

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

Você assinou o dispositivo de um usuário e ele está recebendo mensagens push, mas como é possível cancelar a inscrição?

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

Em sendSubscriptionToServer(), você precisa considerar como processar 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 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 especificados que vão facilitar as coisas (como uma API padrão para acionar mensagens push), mas esta versão permite que você comece a criar mensagens push nos seus apps da Web hoje mesmo.

Como depurar seu app da Web

Durante a implementação de notificações push, os bugs vão aparecer em um destes dois lugares: sua página ou seu service worker.

É possível depurar bugs na página 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.
  2. Acesse chrome://serviceworker-internals e confira o estado dos service workers e os erros, se houver. Esta página é temporária até que o DevTools tenha um conjunto de recursos semelhante.

Uma das melhores dicas que posso dar para quem está começando a usar service workers é usar a caixa de seleção "Open DevTools window and pause JavaScript execution on service worker startup for debugging". 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 que você retome ou avance pelo script do service worker e veja se há algum problema.

Captura de tela mostrando onde a caixa de seleção pausar execução está em serviceworker-internals.

Se houver um problema entre o FCM e o evento de push do seu worker de serviço, não será possível depurar o problema, já que não há como 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. A aparência será mais ou menos assim:

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

Observe a resposta "success": 1. Se você receber uma falha, isso sugere que algo está errado com o ID de registro do FCM e a mensagem 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 Chrome para Android não é óbvia. Acesse chrome://inspect, encontre seu dispositivo e procure um item de lista com o nome "Worker pid:....", que tem o URL do service worker.

Captura de tela mostrando onde os service workers estão no Chrome Inspect

UX para notificações push

A equipe do Chrome está preparando um documento de práticas recomendadas para a UX de notificações push, além de um documento que aborda alguns dos casos extremos ao trabalhar com notificações push.

Futuro da mensagem push no Chrome e na Web aberta

Esta seção detalha algumas partes específicas do Chrome desta implementação que você precisa conhecer e como ela é diferente de outras implementações de navegador.

Protocolo e endpoints de push da Web

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

O protocolo Web Push é 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 é que isso evite a necessidade de se inscrever em chaves de API e enviar dados formatados especialmente, como você precisa fazer com o FCM.

O Chrome foi o primeiro navegador a implementar a API Push, e o FCM não oferece suporte ao protocolo de push na Web. Por isso, o Chrome exige o 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 da Web?

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

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/

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

No momento, não há uma solução para isso, 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, combinar os IDs de assinatura do app nativo e do app 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). O objetivo é usar o protocolo de push da Web quando o padrão for 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. As conexões de WebSocket e EventSource são encerradas 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 push 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 isso exige HTTPS? Como 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 publicados, embora o localhost funcione durante o desenvolvimento.

Como é o suporte a navegadores?

O Chrome é compatível em sua versão estável e o Mozilla está trabalhando no Firefox Nightly. Consulte o bug implementando 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 mostrar uma lista das notificações visíveis no momento. Se você tiver um caso de uso para definir uma data de expiração para a notificação depois que ela for mostrada como criada, adoraríamos saber qual é. Adicione um comentário e vamos encaminhar 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 importa com o tempo que a notificação fica visível, use o parâmetro de tempo de vida (TTL) do FCM. Saiba mais aqui.

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

Há algumas limitações descritas nesta postagem:

  • O uso do CCM do Chrome como serviço push cria vários requisitos proprietários. Estamos trabalhando juntos para ver se algumas delas podem ser suspensas no futuro.
  • Você precisa mostrar uma notificação ao receber uma mensagem push.
  • O Chrome no computador tem a ressalva de que, se o Chrome 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 devemos usar a API Permissions?

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

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 quando o dispositivo do usuário receber o push?

Sempre é necessário mostrar uma notificação ao receber uma mensagem push. No cenário em que você quer enviar uma notificação, mas ela só é útil por 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 passar do tempo de expiração.

Confira mais detalhes aqui.

O que acontece se eu enviar 10 mensagens por 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.