Local notifications – API de notificação local nativa do Sistem Operacional com Javascript – Dica rápida

Tempo de leitura 4 minutos

Isso mesmo que você leu, o Javacript pode diparar notificações nativa do Window, Linux, MacOS, Android e IOS direto do Navegador ou aplicativo nativo/híbrido mobile e desktop que use Javacript.

Estas notificações são MUITO úteis e podem fornecer uma interface simples e que ajuda no engajamento do cliente com seu aplicativo.

Eu considero as local notifications super interessantes como substitutas (ou somando recursos) as notificações “in page” comuns, sabe aquelas que você dispara quando envia um email, salva um registro e coisas do gênero? Essas mesmo, as notificações transacionais.

A vantagem é que a local notificationé visualizada mesmo quando o usuário NÃO está visualizando a página (mesmo assim ela precisa estar aberta), já que é exibida pelo sistema operacional.

Isso quer dizer que você pode executar uma ação demorada no navegador (um upload ou disparar vários emails) e avisar o usuário quando isso terminar, mesmo que ele esteja lendo artigos no meu blog.

Colocando em prática

Para o nosso exemplo eu criei um HTML bem simples, nele teremos um link para o requisitar permissão para notificações (mas você também pode executar assim que a página abrir), um box para mostrar o status atual da permissão e um formulário para criar a notificação com título, data em que será disparada e o conteúdo da mensagem.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        input, textarea {
            display: block;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <a href="" id="request-permission">Solicitar permissão</a>

    <div id="status"></div>

    <form action="" id="form">
        <input type="text" id="notify-title">
        <input type="datetime-local" id="notify-datetime">
        <textarea id="notify-body" cols="30" rows="10"></textarea>
        <input type="submit" value="Enviar">
    </form>

    <script src="script.js"></script>
</body>
</html>

Agora começa a mágica, o arquivo Javascript a seguir está comentado para facilitar o entendimento.

O arquivo deve ficar no mesmo nível do arquivo HTML e com nome script.js, se quiser mudar isso, altere na tag <script> do HTML) .

/**
 * Método que solicita a permissão para Local Notification
 */
const requestPermission = () => {
    // verifico se tem suporte no navegador atual
    if (!('Notification' in window)) {
      console.log('Notification API not supported!');
      return;
    }
    // pego a referência DOM ao box que vai exibir o status
    const status = document.querySelector('#status');
    
    // solicito a permissão e quando o usuário se decidir, armazeno do box status
    Notification.requestPermission(function (result) {
      status.innerText = result;
    });
}

/**
 * Dispara a notificação nativa
 * 
 * @param {*} title título da notificação
 * @param {*} body conteúdo da notificação
 */
const notify = (title, body) => {
    // verifico se tem suporte no navegador atual
    // também verifico se a permissão foi concedida
    if (!('Notification' in window) && status.innerText !== 'granted') {
        console.log('Notification API not supported or denied!');
        return;
    }

    // try e catch gerencia o que acontece se der erro
    try {
        // disparo a notificação
        new Notification(title, { body });
    } catch (err) {
        // se der erro, exibo junto com um trace no console
        console.trace('Notification API error: ' + err);
    }
}

Claro que só declarar os métodos não vai fazer nada, precisamos manipular o DOM e eventos dele para que quando eu clicar no link para solicitar permissões ou enviar o formulário de agendamento de notificações as coisas realmente aconteçam.

O importante aqui é entender que o código acima pode ser utilizado em qualquer lugar que você quiser, da forma que sua imaginação conceber, apenas tomando cuidado com o box de status no método requestPermission.

Agora vamos fazer isso funcionar.

/**
 * Este método inicia tudo
 */
const init = () => {
    // verifico se tem suporte no navegador atual
    if (!('Notification' in window)) {
        console.log('Notification API not supported!');
        return;
    }

    // pego todos os itens do DOM que vou usar
    const requestPermissionLink = document.querySelector('#request-permission'); // link para solicitar permissão
    const status = document.querySelector('#status'); // box de status
    const form = document.querySelector('#form'); // formulário
    const notifyTitle = document.querySelector('#notify-title'); // campo de título
    const notifyBody = document.querySelector('#notify-body'); // campo de conteúdo
    const notifyDatetime = document.querySelector('#notify-datetime'); // compo de data
    
    // adiciono no box de status a permissão atual
    status.innerText = Notification.permission;
    
    // quando clicar no link para solicitar permissão
    requestPermissionLink.addEventListener('click', (e) => {
        e.preventDefault(); // evito a ação principal (que é navegar para o link)
        requestPermission(); // solicito a permissão
    })

    // quando o formulário for enviado
    form.addEventListener('submit', (e) => {
        e.preventDefault(); // evito a ação principal (que é enviar o formulário e recarregar a tela)
        const title = notifyTitle.value; // leio o valor do título
        const text = notifyBody.value; // leio o valor do conteúdo
        notifyBody.value = ''; // apago o valor do conteúdo (só porque ficou mais fácil pra mim usar este mini app)
        
        // notify(title, text); // se quiser disparar a notificação agora apenas descomente a linha

        // eu pego a data informada
        const date1 = new Date(notifyDatetime.value);
        const date2 = new Date(); // pego a data atual
        const scheduleDate = date1 - date2; // calculo a diferença entre as duas (em milisegundos)

        setTimeout(() => notify(title, text), scheduleDate); // uso o setTimeout para agendar a notificação
    })
}

// executo o método init - que inicia tudo
init();

O arquivo está comentado para facilitar o endendimento!

Aqui o arquivo completo e SEM comentários.

const requestPermission = () => {
    if (!('Notification' in window)) {
      console.log('Notification API not supported!');
      return;
    }
    const status = document.querySelector('#status');
    
    Notification.requestPermission(function (result) {
      status.innerText = result;
    });
}

const notify = (title, body) => {
    if (!('Notification' in window) && status.innerText !== 'granted') {
        console.log('Notification API not supported or denied!');
        return;
    }

    try {
        new Notification(title, { body });
    } catch (err) {
        console.trace('Notification API error: ' + err);
    }
}

const init = () => {
    if (!('Notification' in window)) {
        console.log('Notification API not supported!');
        return;
    }

    const requestPermissionLink = document.querySelector('#request-permission');
    const status = document.querySelector('#status');
    const form = document.querySelector('#form');
    const notifyTitle = document.querySelector('#notify-title');
    const notifyBody = document.querySelector('#notify-body');
    const notifyDatetime = document.querySelector('#notify-datetime');
    
    status.innerText = Notification.permission;
    
    requestPermissionLink.addEventListener('click', (e) => {
        e.preventDefault();
        requestPermission();
    })

    form.addEventListener('submit', (e) => {
        e.preventDefault();
        const title = notifyTitle.value;
        const text = notifyBody.value;
        notifyBody.value = '';
        
        // notify(title, text);

        const date1 = new Date(notifyDatetime.value);
        const date2 = new Date();
        const scheduleDate = date1 - date2;

        setTimeout(() => notify(title, text), scheduleDate);
    })
}

init();

Se quiser saber mais sobre este recurso, recomendo:

É isso, até a próxima!

Que saber quando outros artigos como este saírem? Cadastre-se na newsletter.

Autor: Erik Figueiredo

Músico, gamer amador, tutor de programação, desenvolvedor freelancer full cycle, com foco em PHP (Laravel e CakePHP), Javascript (Front e Node.js), Dart (Front e Flutter) e infra.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *