Integrando App Android com o Firebase Cloud Messaging

No post onde explico sobre Push Notification, vimos uma série de problemas que temos ao implementar um sistema de notificação utilizando a arquitetura em que a própria app faz as requisições ao servidor. Nesse post, aprenderemos a implementar uma solução mais adequada para essa necessidade utilizando o FCM (Firebase Cloud Messaging).

Lembrando que estarei utilizando o projeto (de teste) para a casa do código desenvolvido pelo instrutor Matheus Brandino como exemplo.

O pré-requisito para configurarmos o firebase é pelo menos ter uma conta do Google para entrar no sistema. Caso não tenha, crie uma conta.

Nosso primeiro passo é entrar no console do Firebase, pois é a partir dele que criaremos o nosso projeto:

pagina_home

Nessa página, criaremos um projeto que representará o nosso projeto da casa do código, portanto, clique no botão azul “CRIAR NOVO PROJETO”:

criando_projeto

Dê um nome ao projeto, nesse exemplo, utilizarei o nome “cdc teste” e a região marcarei como “Brasil”. Em seguida, clique no botão azul “CRIAR PROJETO”:

overview_firebase

Agora que criamos um projeto no Firebase, precisamos adicionar o Firebase na nossa App, nesse caso, faremos isso para uma App Android, ou seja, clique no círculo verde que tem o robozinho do Android:

inserindo_detalhes

Nesse instante, estamos adicionando o nome do pacote da App, nesse projeto, temos o seguinte pacote: “br.com.caelum.casadocodigo”. A informação de certificado de assinatura é opcional, portanto, não precisamos preenchê-la. Então, clique no botão azul “ADICIONAR APLICATIVO

gerando_json_de_configuracao

Nessa tela, o Firebase envia um arquivo json, via download, de configuração para que adicionemos na nossa App. Observe que é demonstrado o local correto para adicionar o arquivo, ou seja, dentro do diretório “app” conforme abaixo:

adicionando_json

Em seguida, clique em “CONTINUAR”. Agora, o Firebase pede para realizarmos algumas configurações nos arquivos build.gradle tanto no nível projeto quanto no módulo. Então vamos realizar essas modificações.

Primeiro adicionaremos o trecho classpath 'com.google.gms:google-services:3.0.0' no arquivo build.gradle do projeto, ou seja, build.gradle (Project: CasaDoCodigo):

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

//restante do código

Agora, vamos alterar o arquivo build.gradle (Module: app) do módulo, adicionando o plugin 'com.google.gms.google-services':

apply plugin: 'com.android.application'

android {
    // restante do código
}

dependencies {
    //dependências
}

apply plugin: 'com.google.gms.google-services'

O próprio Firebase indica que adicionemos o plugin na parte de baixo do arquivo. Portanto, manteremos o plugin no final do arquivo. Por fim, clique em “Sync now” para sincronizar a configuração que realizamos.

Após a sincronização, no console do Firebase, clique em “FINALIZAR”:

overview_com_app_adicionada

Veja que agora temos um projeto criado! Será que já da pra enviar uma mensagem a partir do Firebase? Até da, porém, ainda não configuramos a nossa App para receber essas mensagens do Firebase. Portanto, iremos configurar agora.

Primeiro, precisamos adicionar a dependência do firebase compile 'com.google.firebase:firebase-messaging:9.0.2' no nosso módulo, pois é a partir dela que teremos acesso às APIs do Firebase para o serviço mensageiro. Então vamos adicioná-la:

dependencies {
    //outras dependências
    compile 'com.google.firebase:firebase-messaging:9.0.2'
}

Clique em “Sync now” para sincronizar o projeto. Finalizando a sincronização, o nosso próximo passo é criar duas classes de configuração, mas, antes de criar essas classes, vamos criar o pacote para elas com o nome "br.com.caelum.casadocodigo.firebase".

A primeira classe que criaremos estenderá da classe FirebaseInstanceIDService do pacote com.google.firebase.iid, portanto, criaremos a classe CDCInstanceIDService:

public class CDCInstanceIDService extends FirebaseInstanceIdService {

}

Essa classe será responsável em receber um token único que o Firebase gera para vincular ao dispositivo, pois, a partir desse token, o Firebase consegue enviar as mensagens para os dispositivos. Para pegarmos esse token, podemos sobrescrever o método onTokenRefresh():

public class CDCInstanceIDService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        super.onTokenRefresh();

        String token = FirebaseInstanceId.getInstance().getToken();
        Log.d("Token da App", token);
    }
}

Esse método pode ser chamado a partir das seguintes ações.

  • Deletando o Instance ID.
  • Restaurando a App em um novo dispositivo.
  • Usuário deletando ou reinstalando a App.
  • Usuário limpando os dados da App.

A próxima classe que criaremos é a CDCMessasingService que estenderá da classe FirebaseMessagingService:

public class CDCMessasingService extends FirebaseMessagingService {

}

Essa é a classe que ficará responsável em receber as mensagens do Firebase, ou seja, a partir dela, a nossa App ficará escutando qualquer requisição referente às mensagens vindas do FCM.

Por fim, precisamos informar ao Android que essas duas classes que criamos, serão Services, ou seja, elas ficarão funcionando em background sem nenhuma intervenção do usuário em interface gráfica! Mas como fazemos isso? Simples! basta adicionar no AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="br.com.caelum.casadocodigo">
    
    <!-- permissions -->

    <application
        android:name=".aplication.CasaDoCodigoStore"
        android:allowBackup="true"
        android:icon="@drawable/casadocodigo"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        <activity android:name=".activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

       <!-- activities -->

        <service android:name=".firebase.CDCMessasingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <service android:name=".firebase.CDCInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>

    </application>
</manifest>

Agora sim podemos testar a nossa App. Ao abrir o emulador, ou então, no seu próprio celular, desinstale a App para garantir que Firebase gere o token sem nenhum problema. Então rode a App:

projeto-cdc-tela-principal

A princípio, não aconteceu nada de diferente, mas se olharmos o logcat:

D/Token da App: cs8iGqkukl0:APA91bEoHd0g6yF2IDy4pufDmuUNxagCQRu0BYp7PsmBA3FmCyuY36DLaQg...

Observe que ele gerou um token para a nossa App, em outras palavras, agora a nossa App e o Firebase estão integrados! Por enquanto, copie o token para podermos enviar uma mensagem para o nosso dispositivo.

Agora, no console do Firebase, vá no menu “Notifications”:

enviando_mensagem

Clique no botão azul “ENVIE SUA PRIMEIRA MENSAGEM”:

notification_send1

Preencha o campo obrigatório “Texto da mensagem” e na opção de segmentação, escolha a opção “Dispositivo único”, e então, cole o token que foi gerado. Mais abaixo, existe as opções avançadas, clique nela:

notification_opt_adv

Veja que temos o campo título, que refere-se ao título que a notificação terá. Portanto, adicione também um título para ela, nesse exemplo, eu adicionei: “Casa do Código”. Em seguida, clique no botão azul “ENVIAR MENSAGEM”:

notification_confirm

Observe que o Firebase mostra um resumo da requisição para que você confirme o envio da notificação, caso estiver tudo correto, apenas clique em “ENVIAR”.

Se a App estiver aberta, nada acontece… Por que será? É justamente porque a API messaging do Firebase quando envia uma notificação, por padrão, envia automaticamente para o Android apenas em background, ou seja, só irá aparecer se não estivermos na App. Portanto, se você estiver com a App aberta, saia da App e reenvie a mensagem no console do Firebase, caso contrário, veja o resultado:

recebendo_notificacao_background

Veja que a notificação aparece! Note também, que quando tocamos nela, ela já abre a activity LAUNCHER, nesse caso a MainActivity. Em outras palavras, sem ao menos pedir para o server, recebemos uma mensagem. Portanto, conseguimos implementar o push notification! 😉

Além de enviar notificações via console, podemos também enviar via HTTP ou XMPP.

No próximo post veremos como podemos receber e exibir uma notificação também em foreground, isto é, com a App aberta.

E aí, o que achou do Firebase? Pretende utilizá-lo nos seus projetos atuais ou futuros? Deixe seu comentário sobre o que achou ou sua experiência durante a implementação.

Curtiu essa dica? Quer aprender mais ou iniciar sua carreira como um dev Android? na Alura, agora temos os cursos online para a carreira de dev Android Jr, onde você aprenderá a criar a sua App do início ao fim com muita prática!

Fique por dentro

(Última atualização em: 1 de junho de 2017)

Content Editor at Alura and Software Developer

  • Pingback: Blog da Alura – O que é Push Notification?()

  • Felipe F. Schwade

    Achei muito interessante o funcionamento da ferramenta, pretendo utilizá-la em um projeto futuro.

    • Bacana Felipe! A melhor forma de conhecermos mais ainda sobre uma ferramenta é fazendo uso em um projeto nosso. Depois comente conosco como foi sua experiência 😀

  • Para quem trabalha com PHP, isso vai auxiliar
    https://packagist.org/packages/valdeirpsr/firebasemessaging-php

  • Cesar

    Mto bom, estou procurando informação sobre esse assunto.. Seria muito bom se na Alura tivesse um curso de persistencia para android usando o Firebase, seria otimo e de grande ajuda.

    • Olá Cesar, tudo bem? Está nos nossos planos criar cursos sobre o Firebase, porém, até o momento não temos previsão para o lançamento. Entretanto, você pode adicionar a sua sugestão nesse link.

  • Alex Felipe, nesse caso, como eu posso gerenciar os tokens que são gerados pelo celular, por exemplo, suponha que eu precise primeiro pegar o token de 3 dispositivos através de minha aplicação java (server side) para poder enviar via HTTP Rest? não vi no firebase nenhum local que dê para gerenciar esses tokens.

    • Olá mfilhow, tudo bem? Ótima observação! Quando estamos utilizando o Firebase precisamos fazer na mão essa “checkagem”, ou seja, temos que fazer esse tratamento dentro do método onTokenRefresh() da classe FirebaseInstanceIdService. Por exemplo, a sugestão que a própria documentação do FCM faz é que implementemos um método que ficará responsável por isso, poderia ser um enviaTokenParaServidor():

      public class CDCInstanceIDService extends FirebaseInstanceIdService {
          @Override
          public void onTokenRefresh() {
              super.onTokenRefresh();
      
              String token = FirebaseInstanceId.getInstance().getToken();
              Log.d("Token da App", token);
              enviaTokenParaServidor(token);
          }
      
          public void enviaTokenParaServidor(String token){
              //implementação para enviar para o servidor o token
          }
      }
      

      E então, dentro dessa implementação, você escreve um código que fica responsável em enviar o token. Era basicamente isso que você precisava?

      Abraços.

      • Opa Alex, Isso talvez ajude sim e muito na verdade. Pelo que eu entendi dessa forma eu consigo utilizar somente o serviço de FCM e consigo deixar os tokens sincronizados com cada usuario nosso (sem utilizar o serviço de database do firebase), podendo assim manter os tokens no meu backend (java project), permitindo que eu possa montar campanhas de marketing para clientes especificos. Muito obrigado pela resposta.

        • Exato mfilhow! Uma das vantagens de usar o FCM é que você não fica acoplado com todo toolkit dele, ou seja, o realtime database, o próprio database entre diversos outros módulos. Em outras palavras, temos uma flexibilidade enorme, pois podemos fazer o que bem entendermos com os nossos clientes já que temos acesso ao token que nos permite enviar as mensagens desejadas.

          Qualquer dúvida é só falar 🙂

          Abraços.

  • Diego Romero

    Gostaria que houvesse uma sessão de screencasts no alura, acho que seria mais rápido pro autor do conteúdo ao invés de ficar tirando esse monte de print e digitando detalhes de cada print, seria mais cômodo tanto pro autor explicar determinado assunto, como também pra nós usuários da plataforma. Lembrando que seria somente um único vídeo pra cada tipo de assunto, então poderiam estender o tempo do mesmo sem problema algum.

    • Alex Felipe

      Olá Diego, tudo bem? Eu passei para a equipe responsável pelo blog sobre sua sugestão, obrigado!

      Abraços.

  • Grégori Machado

    Opa. Parabéns, muito bem explicado. Estou com uma dúvida. Eu já tenho uma aplicação android com backend na google cloud, se ao invés de criar um projeto novo eu importar aquele projeto para o firebase(porque ele dá essa opção) também funciona? Estou tentando fazer isso na minha aplicação.

    • Alex Felipe

      Oi Grégori, tudo bem? Muito obrigado pelo feedback e fico contente que tenha gostado! 🙂

      Em relação a sua dúvida, acredito que funciona sim, entretanto, o Firebase foi desenvolvido para que exista um modelo de aplicação conhecido como “serverless”. Em outras palavras, nesse tipo de arquitetura, o desenvolvedor não se preocupa em codificar ou manter o código no lado do backend, isto é, do lado do servidor. Isso pode ser bom e ruim ao mesmo tempo.

      Motivos que são bons:

      Não precisa se preocupar em realizar a manutenção do cídigo.
      Toda a responsabilidade em tratamento de dados é delegada para o Firebase.
      Basta apenas consumir a API sem perder tempo pensando na implementação do projeto.

      Motivos que são ruins:

      Não existe controle por conta do desenvolvedor no lado do backend, ou seja, se um dia vc quiser implementar alguma regra específica, não será possível dependendo da ferramenta que utilizar.
      Você fica totalmente dependente do Firebase. Em outras palavras, se um dia o Firebase anunciar que vai morrer ou algo do tipo, você simplesmente vai ter que se virar nos 30 para realizar uma migração da aplicação.

      Esses são os detalhes a nível de desenvolvimento, existem outros que fazem parte de cada um dos módulos do Firebase e que são detalhados na documentação, por isso não mencionei.

      Resumindo: Para uma aplicação acadêmica ou de teste eu acredito que vale a pena usar o Firebase por completo justamente para testar todas as funcionalidades que ele provê, entretanto, para uma aplicação real, no meu ponto de vista, não vale a pena migrar justamente pela falta de controle por usar esse conceito de serverless. Mas é claro, usar um módulo ou outro, não tem problema nenhum, por exemplo, usar o FCM ou o Authentication para resolver problemas específicos, porém, para persistir seus dados e tratá-los, isto é, fazer todo o papel de um servidor, faz mais sentido codificar o seu próprio justamente para que você tenha mais controle.

      • Grégori Machado

        Muito obrigado cara. Pois é, já tenho todo o backend que fiz no app engine, eu queria só o módulo de notificações de push do firebase. Porém não estou conseguindo integrar. Aparentemente está tudo certo, mas as notificações não aparecem na app.

        • Alex Felipe

          De nada Como você está mandado as requisições para o Firebase?

          • Grégori Machado

            eu fiz exatamente como está no tutorial, só que ao invés de criar um novo projeto eu importei o meu do app engine.

          • Alex Felipe

            Estranho, deveria aparecer sem nenhum problema, se quiser, pode mandar o link do Github, e então, eu vejo se tem algum detalhe.

  • Pingback: Tratando notificações recebidas do Firebase no Android - Blog da Alura: desenvolvimento, design e muita tecnologia()

  • Roberto

    Olá, achei muito bom o post, porém não está gerando o token. Quando eu coloco o trecho no manisfest ele diz : Validates resource references inside Android XML files.
    Como eu poderia resolver isso?

    • Alex Felipe

      Olá Roberto que bom que gostou, porém, você poderia mandar o seu Manifest para eu dar uma olhada? Pode ser algum tipo de detalhe pequeno que não é possível apontar apenas com o nome do erro.

      Abraços.

      • Roberto

        Ola Alex, consegui resolver o problema. Agora minha dúvida é: Se o usuário instalar a aplicação via GooglePlay por exemplo, e eu quiser mandar uma notificação exclusiva para ele, é possível ?

        • Alex Felipe

          Oi Roberto, é possível sim, o token que é gerado pelo FCM é o próprio ID que representa o dispositivo e app do usuário. Portanto, o que você precisa é de fato enviar o token, assim que ele for gerado, para um servidor por exemplo, armazernar o token de alguma forma que você vincule com o seu usuário, e então, você faz as request para o FCM diretamente no servidor por meio do protocolo HTTP ou XMPP. Basicamente são esses os passos que precisam ser feitos. Infelizmente eu não tenho um tutorial dando um exemplo de como isso pode ser feito, porém, futuramente, eu pretendo fazer.

          Abraços.

      • Roberto

        Mais uma duvida. É possível eu atumatizar o envio de notificações? Por exemplo, todo o dia de manha se estiver chovendo meu sistema identifica chuva, ai quero enviar uma notificação para meu usuário. É possível que isso seja feita de forma automática?

        • Alex Felipe

          Sim, é possível, basta apenas você implementar o código que enviará as requisições para o FCM, ou seja, independentemente de quando você for mandar, basta apenas você fazer uso da sua implementação que faz as requisições para o FCM enviar as notificações.

          • Roberto

            Hum, entendi mais anida esta um pouco abstrato para mim. Qual codigo é esse, que envia as requisições para o FcM? Ou onde eu encontro/implemento? Nao entendi mt bem.

          • Roberto

            Hum, entendi mais anida esta um pouco abstrato para mim. Qual código é esse, que envia as requisições para o FcM? Ou onde eu encontro/implemento? Nao entendi mt bem. Olha, super apoio se você quiser fazer um post sobre automatização de notificações! rsrs 😉

          • Alex Felipe

            De fato para explicar todas as suas dúvidas será necessário criar um artigo sobre isso, pois existem diversos detalhes que precisam ser explicados, eu vou marcar no meu backlog para que seja feito, tudo bem? Obrigado pela sugestão.

            Abraços.

          • Roberto

            PERFEITO, muito obrigado!!! E parabéns pelos posts viu!!!

          • Roberto

            Uma coisa interessante seria também fazer das demais ferramentas do Firebase, como o Database.

          • Alex Felipe

            Eu vou adicionar também, sempre que tiver sugestões de posts fique a vontade para mandar, todas as sugestões são anotadas e enviadas para o time de edição de conteúdo. Se preferir, pode me mandar um e-mail também que sou responsável pelo blog -> alex.vieira@caelum.com.br

            Abraços.

  • Alisson Lopes

    Muito bom esse artigo, mas alguém sabe como implementar essa plataforma dentro de apps desenvolvidos no Cordova? Não sei muito bem trabalhar com Java e para meu projeto atual o Cordova me satisfaz em tudo.

    • Alex Felipe

      Obrigado pelo feedback Alisson! 🙂

      Sobre o Cordova eu nunca fiz uso dele, porém, provavelmente existem plugins ou algo do gênero feito pela comunidade para conseguir fazer uso do FCM. Fiz uma breve pesquisa e achei esse projeto -> https://github.com/fechanique/cordova-plugin-fcm. talvez lhe atenda.

      Abraços.

  • Edivaldo Silva

    Bom dia!!!! Funciona com a aplicação fechada? Pois fiz um teste no console do firebase e não chegou a notificação com ela fechada. Alguém pode ajudar?

    • Alex Felipe

      Oi Edivaldo, funciona sim! Pois mesmo fechando a tela da aplicação ela ainda está funcionando em background.

      O que pode acontecer é caso você forçar o fechamento da aplicação via configurações do Android, nesse caso não vai funcionar até você abrir a aplicação novamente, pois de fato a sua aplicação não está mais funcionando, ou seja, vai precisar abrí-la novamente.

      Ou então, caso a sua conexão com a rede for muito precária, nesses casos, até estabelecer uma conexão com a internet estável a notificação não será recebida.

      Caso não entrou em nenhuma destas situações, provavelmente foi alguma falha nos passos da configuração. Geralmente, acontece quando tenta baixar o arquivo JSON, ou então, quando a aplicação possui dependências que use alguma api do play services com uma versão diferente à do firebase cloud messaging.

      Lembrando que todas as configurações são necessárias!

      Se for o caso, me manda o código que foi feito via github, dessa forma posso verificar se tem algum detalhe.

      Abraços.

      • Edivaldo Silva

        Minha dúvida era so com a tela fechada (fecho também o aplicação no android), não deixando nada dela em aberto. Hoje notei que se abro a tela e ela fica em background, depois de uns 10 minutos ela não recebe mais as notificações, porque? Só abrindo o programa novamente.

        • Alex Felipe

          Além dos cenários aos quais mencioneis, existem outros pontos do FCM que podem impactar, como por exemplo a prioridade da mensagem, caso for a default pode ser que seja o motivo para não chegar rapidamente… Nesse link https://firebase.google.com/docs/cloud-messaging/concept-options?hl=pt-br está todo conteúdo sobre mais detalhes que opções avançadas do FCM. Recomendo a leitura.

  • Edivaldo Silva

    Bom dia!!!! Funciona com a aplicação fechada? Pois fiz um teste no
    console do firebase e não chegou a notificação com ela fechada. Alguém
    pode ajudar?

  • joao neto

    Meus parabéns, você se superou com esse post, é uma verdadeira aula. Muito Obrigado por compartilhar isso com a comunidade! Abraços.

    • Alex Felipe

      Opa João, muito obrigado pelo feedback! Fico bem contente que tenha gostado 🙂

      Abraços!

  • Wesley Chaves

    a grande questão e fazer a mensagem enviada aparecer no app quando clicada …. se já tiver algo do tipo adoraria conferir…. 😉

    • Alex Felipe

      Opa Wesley, blz? Podemos fazer isso quando tratamos a notificação manualmente, veja uma forma de fazer isso nesse post -> http://blog.alura.com.br/tratando-notificacoes-recebidas-do-firebase-no-android/

      Lembrando que é muito importante consultar sempre a documentação do FCM para tirar dúvidas técnicas https://firebase.google.com/docs/cloud-messaging/?hl=pt-br

      Uma sugestão também é verificar sobre a forma na qual a notificação é enviada, pois existem duas estruturas a primeira seria a notification e a outra seria a data, recomendo considerar a data para ter mais poder de manipulação 🙂

      Abraços.

      • Wesley Chaves

        gostaria muito de vê algum exemplo em código…

  • Henrique Mendes

    Bom dia!

    Segui as instruções mas minha mensagem no firebase é a seguinte:
    https://uploads.disquscdn.com/images/814a062b2f9dfcec141669437ab4fe99a537faea33ecacc67c14f4a648e20cc3.png

    Não estou sabendo resolver, pode me ajudar?

    • Alex Felipe

      Oi Henrique, blz? Pelo o que tudo indica o problema está no registro de token do Firebase na sua App. Tente pegar novamente o toke que foi registrado na app usando o seguinte código:


      String token = FirebaseInstanceId.getInstance().getToken();
      if (token != null)
      Log.i("token firebase", token);

      Pode executá-lo na sua activity principal mesmo, o if é apenas para não quebrar a aplicação, pois pode ser que o token não tenha sido gerado ainda.

      []s

      • Henrique Mendes

        Eu uso este código, como é descrito aqui e na documentação do firebase, mas não funciona.

        public class FirebaseRegistrationIntentService extends FirebaseInstanceIdService {
        @Override
        public void onTokenRefresh() {
        super.onTokenRefresh();

        String token = FirebaseInstanceId.getInstance().getToken();
        Log.d("Token da App", token);
        }

        }

        Com mais detalhes está minha pergunta no stackoverflow:
        https://pt.stackoverflow.com/questions/234478/token-de-registro-n%C3%A3o-registrado-firebase

Próximo ArtigoBoas práticas de desenvolvimento PHP