Push notifications com Firebase Cloud Messaging

Push notifications com Firebase Cloud Messaging
Leonardo Marinho
Leonardo Marinho

Compartilhe

Hey, psiu! Opa, tudo bem? Já parou para pensar que às vezes precisamos enviar um psiu para nossos usuários de aplicativos para chamar a atenção deles, igual fiz com você agora? Os usuários perdem o interesse muito rápido em um aplicativo se não enviarmos mensagens que os lembrem de abri-lo por alguma razão. Pensando nisso, a Google criou o Firebase Cloud Messaging, que é uma solução para realizar o envio de mensagens do tipo push para dispositivos móveis Android e iOS e também para aplicações web.

Notificação push

As notificações push são as famosas “cenourinhas” para atrair o “coelho”. No caso, o coelho são os usuários e a cenoura são notificações de promoção, uma nova curtida em uma foto, um novo comentário em uma rede social ou similares. É através das notificações que fazemos os usuários abrirem o aplicativo. Não é regra, pois um usuário pode simplesmente ignorar a notificação enviada, mas normalmente as pessoas abrem. Em uma tradução livre, push notification é uma “notificação empurrada”, ou seja, é uma notificação que o usuário não necessariamente solicitou, mas que concordou em receber ao instalar o aplicativo. Vamos ver um exemplo menos abstrato? Imagine que a Casa do Código tenha um aplicativo para seus leitores e leitoras receberem notificações todas as vezes que um livro novo for lançado. Para isso, o fluxo que seria criado para a notificação é o seguinte:

Diagrama de fluxo de uma notificação de push saindo do servidor da casa do código e viajando pela internet até chegar ao usuário

Uma das grandes vantagens de implementar esse tipo de notificação em seu aplicativo é poder monitorar a porcentagem de usuários que recebem, abrem, ignoram etc. as suas notificações. Desta maneira é possível mapear quais campanhas publicitárias fazem mais sentido de acordo com um determinado público. Essa abordagem de fazer com que o aplicativo seja receptor, isto é, fique esperando requisições, chamamos de Push Notification. Atualmente, existem algumas plataformas que oferecem esses serviços mensageiros, como o FCM (Firebase Cloud Messaging).

Banner da Escola de Mobile: Matricula-se na escola de Mobile. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

Configurando o Firebase

Primeiro, antes de mais nada, você precisa ter uma conta Google (Gmail), que será utilizada para acessar o console de desenvolvedor do Firebase. Para isso, acesse: https://firebase.google.com/ e clique em “Ir para o console”.

Imagem da tela principal do Firebase com uma seta apontando para um botão na parte superior direita na tela, no qual aparece escrito “Ir para o console”

Feito isso, precisamos criar um projeto no Firebase para que possamos comunicar a nossa aplicação Flutter com ele posteriormente. Para isso, já na tela do console Firebase, crie um projeto.

Imagem da tela do console Firebase com uma seta apontando para o botão de “Criar um projeto”

Na próxima tela que se abrirá, digite um nome para o projeto. No nosso caso, optamos por utilizar o nome alura-notifications, mas você pode utilizar qualquer nome que faça sentido para o seu projeto. Após apertar em continuar, aparecerá uma nova tela com detalhes sobre o Google Analytics. Deixe esta opção habilitada! É ela que nos fornecerá os dados do Cloud Messaging futuramente.

Em seguida, ajuste a sua conta no Google Analytics utilizando as configurações padrão oferecidas. Agora, é só apertar no botão de “Criar projeto” e observar a mágica acontecer! Vai aparecer uma tela com a mensagem “Criando o projeto” (normalmente esta etapa leva alguns segundos para terminar de executar).

Imagem do console Firebase mostrando a mensagem de que está criando o projeto

Após a criação do projeto ser realizada, aperte o botão que aparecerá escrito “Continuar” e você cairá na tela principal do seu projeto Firebase. Após estar na tela principal, selecione o sistema operacional em que a sua aplicação está executando. No nosso caso, ensinaremos a integração do Firebase com o sistema operacional Android. Então, selecione esta opção para obter o guia de instalação e configuração do Firebase para esta plataforma.

Imagem da tela principal do projeto com uma seta apontando para o botão da plataforma Android

A tela que abrirá tem três opções, mas agora precisamos preencher apenas uma, que é o nome do pacote do Android. Caso já tenha criado o seu projeto Flutter, para acessar o nome do pacote, abra a pasta android e navegue até o arquivo AndroidManifest.xml, que está localizado em: seu_projeto > android > app > src > profile > AndroidManifest.xml. Nesse arquivo, você consegue obter o package. Caso não tenha criado, pode especificar o nome e a empresa que deseja e seu projeto terá como resultado o pacote que quiser. No nosso caso, ficou com.example.alura_notification.

Print do Intellij navegando pelas pastas do projeto alura notifications, criado em Flutter, até o arquivo arquivo AndroidManifest.xml para obtermos o package “com.example.alura_notification”

Após preencher o campo com o package do projeto, clique em próximo. Agora, você está em uma das telas mais importantes de toda a configuração do Firebase. Baixe para o seu computador o arquivo google-services.json, que será a nossa credencial de acesso ao Firebase no lado do aplicativo. Coloque este arquivo dentro do seu projeto Flutter no seguinte diretório: seu_projeto > android > app > google-services.json. Se este arquivo não estiver localizado na pasta app, que fica dentro da pasta android do projeto Flutter, pode esquecer! Vai dar treta! Ele é o nosso passaporte para conversar com o Firebase.

Imagem mostrando a tela para download do google-service.json disponível para download

O plug-in dos serviços do Google para Gradle carrega o arquivo google-services.json, cujo download você acabou de fazer. Modifique seus arquivos build.gradle para usar o plug-in. O arquivo build.gradle fica na raiz da pasta android. Verifique se o seu arquivo build.gradle está similar ao código abaixo:

buildscript {
  repositories {
    // Verifique se o seu arquivo tem esta linha, caso não tenha, adicione-a:
    google()
  }
  dependencies {
    ...
    // Adicione esta linha para a leitura do arquivo .json do Firebase
    classpath 'com.google.gms:google-services:4.3.5'
  }
}

allprojects {
  ...
  repositories {
    // Verifique se o seu arquivo tem esta linha, caso não tenha, adicione-a:
    google() 
    ...
  }
}

Agora, vá no arquivo build.gradle, que está dentro da pasta app, e adicione as dependências do Firebase e do Google Services seguindo o exemplo do código abaixo:

apply plugin: 'com.android.application'

// Adicione esta linha
apply plugin: 'com.google.gms.google-services'

dependencies {
  // Dependências necessárias, adicione-as!
implementation platform('com.google.firebase:firebase-bom:26.2.0')
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.firebase:firebase-analytics'

 }

Feito isso, volte ao console do Firebase, aperte o botão de “Próximo” e pronto! Temos o Firebase configurado. Novamente, na tela principal do projeto alura-notification, role a página até chegar na opção “Cloud Messaging”. Guarde ela! Já já voltaremos para disparar a nossa primeira notificação a partir de lá!

Integração do Flutter com o Firebase Cloud Messaging

Configurado o Firebase com a parte nativa Android, agora é com o Flutter! Utilizaremos a extensão firebase_messaging criada especialmente para conectar o Flutter com o FCM. Adicione a declaração desta extensão na área das dependências do seu projeto no arquivo pubspec.yaml.

A versão atual da extensão firebase_messaging é a 7.0.3.

O seu arquivo pubspec.yaml deverá ficar similar ao nosso:

name: alura_notification
description: A new Flutter project.

publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.1

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter

flutter:
  uses-material-design: true

Adicionada a dependência, agora precisamos importá-la no arquivo main.dart! Para isso, insira a seguinte linha no topo do arquivo:

import 'package:firebase_messaging/firebase_messaging.dart';

Agora, adicione o código que captura os eventos enviados pelo Firebase Cloud Messaging dentro do widget principal. O código é:

    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );

    _firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print('Push token gerado: $token');
    });

Insira este código dentro de um método sobrescrito chamado initState(). O Firebase gera um token único para o seu dispositivo que é recebido através do método getToken(). Este token pode ser enviado para alguma API ou banco de dados e com ele é possível enviar uma notificação de push para o seu dispositivo em específico. Caso não queira enviar direcionadamente, sem problemas! Não precisa salvar este código, pois é possível enviar uma mensagem direcionada a todos os usuários de uma única vez através do painel do FCM. Feitas essas configurações no código Flutter, o seu arquivo main.dart deve ficar similar a:

import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

  @override
  void initState() {
    super.initState();
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );

    _firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print('Push token gerado: $token');
    });
  }

  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Na real, o que temos com este código é um aplicativo padrão de contador criado em Flutter, mas que por baixo dos panos suporta o recebimento de Push Notifications. A tela do aplicativo ficará da seguinte maneira:

Imagem da tela do emulador Android com o contador padrão de taps no botão flutuante que o Flutter como projeto inicial

Disparando uma notificação

Para realizar o disparo das notificações existem dois caminhos. O primeiro é integrando uma aplicação servidora que você disponha junto ao Firebase Cloud Messaging através da API que ele contém ou através do próprio painel de desenvolvedores. Neste caso, optamos pelo painel de desenvolvedores por ser uma proposta bastante clara e objetiva para um artigo. :)

Bora lá então? No painel do projeto alura-notifications que criamos, acesse o Firebase Cloud Messaging. Caso ainda não tenha criado nenhuma notificação anteriormente, será exibida para você a tela de “Enviar a sua primeira mensagem”, como na imagem abaixo:

Tela do console de desenvolvedores Firebase exibindo um botão em inglês escrito “Enviar a sua primeira mensagem"

Após entrar na tela de envio de mensagens, preencha o título e o texto que aparecerá na notificação. Ao fazer isso, você pode apertar o botão de “Enviar uma notificação de teste”, como a imagem abaixo mostra:

Tela do console Firebase com as opções de preenchimento dos dados para a realização do envio de uma mensagem de push de teste

Repare que ao apertar no botão “Enviar mensagem de teste”, será solicitado um token de registro do FCM. Este token é o que a nossa aplicação Flutter recebe quando se conecta com o FCM. No nosso caso, o código que está responsável por esta captura é:

    _firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print('Push token gerado: $token');
    });

Este código exibe para nós no terminal de execução do IntelliJ qual foi o token gerado para o nosso dispositivo. Todas as vezes que abrimos o aplicativo, ele exibe este token no terminal.

Atenção: certifique-se de que o seu emulador ou dispositivo físico estão conectados à internet para a obtenção do token via Firebase Cloud Messaging.

Push token recebido pelo aplicativo através do FCM e exibido no terminal do Intellij

Copie apenas o Push Token e cole na janela do FCM, aperte o botão de adicionar, que é representado por um sinal de +, e deverá ficar da seguinte maneira:

Imagem do push token sendo inserido no terminal do Firebase Cloud Messaging

Agora, é só enviar o Push de teste apertando o botão “Testar”.

Atenção: o envio da notificação pode ser instantâneo ou não. Houve testes no meu código que demoraram em torno de 5 minutos para a notificação chegar. Outros instrutores aqui da Alura também reportaram atrasos significativos na chegada das notificações. Então, sem treta! Às vezes demora mesmo e não é culpa sua.

Print da tela de um emulador Android exibindo a notificação de push recebida pelo aplicativo

Oba! Recebemos o nosso push notification com sucesso! Mas lembra que temos mais códigos que tratam push no aplicativo? Eles recebem os dados provenientes da notificação. Conseguimos capturar os dados e exibir no terminal ou ainda exibir na própria tela!

Texto da notificação sendo recebido pelo aplicativo, mostrado no terminal do Intellij.

O onMessage é disparado quando o push chega com o aplicativo aberto. O onResume é executado quando o aplicativo está minimizado, recebe uma notificação e é aberto. E o onLaunch é executado quando o aplicativo é aberto através da notificação recebida.

Para recapitular, vamos rever o código?

    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );

Repare que na mensagem capturada pelo aplicativo e exibida pelo console do Intellij, existe um acesso ao objeto chamado data. E que está vazio. Podemos passar instruções ao aplicativo através do data partindo do console do Firebase até o dispositivo móvel.

onMessage: {notification: {title: Hello World, body: Olá, alura aqui!}, **data: {}**}

Também é possível, por exemplo, enviar um ícone para personalizar a exibição da notificação.

Conclusão

Ufa, que maneiro que você chegou até aqui! Aprendemos um montão de coisas! Neste artigo vimos como configurar o Firebase Console, como configurar a parte do Firebase Cloud Messaging (FCM), aprendemos a configurar as dependências dentro do projeto nativo Android, instalamos e configuramos o plugin do FCM para Flutter e enviamos uma notificação, partindo do console FCM para um dispositivo específico (no caso, o nosso app), através do Push Token que foi gerado.

Os códigos deste artigo estão disponíveis neste repositório do GitHub.

Vale lembrar que para o código funcionar, você precisa gerar o seu arquivo google-services.json e colocá-lo na pasta android/app.

Muito obrigado por chegar até aqui e espero, de verdade, que tenha sido um conhecimento útil e que agregue positivamente para a sua carreira!

Referências

Leonardo Marinho
Leonardo Marinho

Leonardo é graduado em Análise e Desenvolvimento de Sistemas. Atualmente é mestre em informática pela UFRJ. Desenvolvedor Full Stack apaixonado por criar aplicativos para dispositivos móveis com tecnologias como Ionic e Flutter. Está se aventurando pelo universo da ciência de dados. Organizador da conferência OpenLabs, atualmente a maior conferência tecnológica da região serrana fluminense. É membro fundador da comunidade Dart Lang Brasil. Gosta de Star Wars e Café.

Veja outros artigos sobre Mobile