Tratando notificações recebidas do Firebase no Android

Alex Felipe
Alex Felipe

Compartilhe

Vamos ver como tratar as notificações do Firebase.

No artigo onde vimos como configurar o FCM (Firebase Cloud Messaging) e integrar com a nossa App Android. Fizemos um pequeno exemplo de envio de notificação, porém, no exemplo que vimos, a notificação não aparecia em foreground, ou seja, enquanto estávamos com a App aberta. Em outras palavras, queremos obter um resultado conforme o exemplo abaixo:

recebendo_notificacao_foreground

Como podemos fazer isso? Atualmente, a classe que fica responsável em receber as mensagens do FCM está com o seguinte código:


public class CDCMessasingService extends FirebaseMessagingService { }

O que será que podemos fazer para que, de alguma forma, consigamos receber a mensagem do FCM dentro dessa classe? Será que existe algum método que podemos sobrescrever? Para a nossa felicidade, existe sim! :D

Pegando a mensagem do FCM

De acordo com a documentação do FCM para envio de mensagens, para que consigámos receber e tratar mensagens dentro da nossa App, precisamos sobrescrever o método onMessageReceive() dentro da classe FirebaseMessagingService. Portanto, faremos isso:


public class CDCMessasingService extends FirebaseMessagingService {
@Override public void onMessageReceived(RemoteMessage remoteMessage) { }
}

A partir desse método, quando a nossa App estiver aberta, receberemos a notificação do FCM e ela será representada pelo parâmetro remoteMessage. Mas e depois? Aparecerá a notificação automaticamente como vimos anteriormente? Nesse caso não, pois recebemos apenas a mensagem. Em outras palavras, precisamos criar a notificação manualmente.

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!

Criando a notificação no Android

Já que estamos recebendo uma notificação, podemos extraí-la para um objeto do tipo RemoteMessage.Notification:


@Override public void onMessageReceived(RemoteMessage remoteMessage) { 
    RemoteMessage.Notification notification = remoteMessage.getNotification();
}

Em seguida, vamos criar um método que vai criar e exibir uma notificação do Android. Portanto, vamos criar o método mostrarNotificacao() que recebe um objeto do tipo RemoteMessage.Notification:


public class CDCMessasingService extends FirebaseMessagingService {
@Override public void onMessageReceived(RemoteMessage remoteMessage) {
     RemoteMessage.Notification notification = remoteMessage.getNotification(); 
     mostrarNotificacao(notification); 
}
public void mostrarNotificacao(RemoteMessage.Notification notification) { } }

Agora que criamos o método, o que precisamos fazer? Criar de fato a notificação que será exibida para o usuário, certo? No Android, temos a classe Notification que permite criarmos notificações. Porém, da mesma forma como vimos no [**AlertDialo**](https://www.alura.com.br/artigos/criando-caixas-de-dialogo-no-android-dialogs), é recomendado que utilize a classe interna Builder` para criarmos as notificações. Portanto vamos utilizá-la:


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    Notification.Builder builder = new Notification.Builder(this);
}

Por questões de compatibilidade, é recomendado que utilizemos a classe NotificationCompat. Em outras palavras, por meio dela, daremos suporte para versões do Android mais antigas. Portanto, vamos utilizá-la ao invés da Notification:


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
    }

Você pode estar se perguntando do motivo de estarmos passando o this por parâmetro do NotificationCompat.Builder(), já que não estamos em uma Activity ou Context. Um detalhe curioso sobre a classe FirebaseMessagingService é que ela, bem internamente, contém uma herança de Context, portanto, podemos utilizá-la! :D

Agora que instanciamos o builder, precisamos montar a notificação. Para isso temos que, pelo menos, preencher 3 informações:

  • Título.
  • Mensagem.
  • Ícone.

Para adicionar um título, basta apenas utilizarmos o método setContentTitle() enviando uma String como parâmetro. Mas calma aí, qual String mandaremos? Lembra que temos o parâmetro notification? Então, nesse parâmetro temos todos os dados que uma notificação do FCM pode ter, portanto, vamos extrair o título por meio do método getTitle():


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    String titulo = notification.getTitle(); 
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
    builder.setContentTitle(titulo); 
    }

E pra adicionar uma mensagem? Simples, da mesma forma como vimos no builder do AlertDialog, a maioria dos métodos do builder também nos devolve o objeto. Em outras palavras, basta apenas chamarmos o método que adiciona a mensagem após o momento em que inserimos o título, nesse caso, o método setContentText():


String titulo = notification.getTitle(); 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
builder.setContentTitle(titulo).setContentText("");

Mas qual mensagem enviamos para ele? Da mesma forma como fizemos com o título, podemos também pegar a mensagem do objeto notification a partir do método getBody():


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    String titulo = notification.getTitle(); 
    String mensagem = notification.getBody(); 
    builder.setContentTitle(titulo).setContentText(mensagem);
}

Agora que temos um título e uma mensagem, precisamos apenas adicionar um ícone. Podemos fazer isso por meio do método setSmallIcon(). Mas qual ícone podemos utilizar? Nesse projeto, temos o ícone da própria App no local R.drawable.casadocodigo, ou seja, vamos utilizá-lo:


.setSmallIcon(R.drawable.casadocodigo) }

Da mesma forma como vimos no AlertDialog, finalizamos a builder com o método build():


builder.setContentTitle(titulo) 
       .setContentText(mensagem); 
       .setSmallIcon(R.drawable.casadocodigo) 
       .build();

Utilizando o serviço de notificações do Android

Se executarmos a nossa App nesse exato momento, a notificação não aparece! Por que será? Diferente do Dialog, as notificações fazem parte de um serviço gerenciado pelo sistema operacional, nesse caso o Android, ou seja, precisamos pedir para o Android esse serviço. Para isso, utilizamos o método getSystemService():


builder.setContentTitle(titulo) 
       .setContentText(mensagem); 
       .setSmallIcon(R.drawable.casadocodigo) 
       .build(); 
        getSystemService();

Porém, precisamos especificar qual serviço queremos enviando uma String por parâmetro. Qual String podemos enviar? A classe Context contém algumas constantes referentes a esses serviços e, para a nossa felicidade, ela contém a constante NOTIFICATION_SERVICE que refere-se justamente ao serviço de notificação que desejamos. Portanto vamos pedir esse serviço:


builder.setContentTitle(titulo) 
       .setContentText(mensagem); 
       .setSmallIcon(R.drawable.casadocodigo) 
       .build(); 
        getSystemService(Context.NOTIFICATION_SERVICE);

Agora precisamos referenciar esse serviço. Por padrão, ele nos devolve um Object, porém, precisamos de alguém mais específico! Qual classe podemos referenciar? No Android, temos a classe NotificationManager que é um classe responsável em gerenciar notificações do Android. Então vamos refenciar essa classe adicionando um cast, pois temos a "certeza" que é essa classe que será retornada:


builder.setContentTitle(titulo) 
       .setContentText(mensagem); 
       .setSmallIcon(R.drawable.casadocodigo) 
       .build(); 
       NotificationManager notificationManager = (NotificationManager) 
       getSystemService(Context.NOTIFICATION_SERVICE);

Exibindo a notificação

A partir do objeto notificationManager, para exibirmos a notificação, basta apenas chamarmos o método notify() enviando dois parâmetros:

  • 1º parâmetro: id da notificação (Esse id é um valor único para a notificação que está sendo criada dentro da App).
  • 2º parâmetro: um objeto do tipo Notification.

Como primeiro parâmetro, podemos enviar qualquer valor, portanto, colocarei como 0. Porém, e o objeto do tipo Notification? Como podemos enviá-lo sendo que temos apenas o builder do tipo NotificationCompat.Builder?

Lembra do método build()? Adivinha o que ele retorna? É exatamente o que você está pensando! Um objeto do tipo Notification, em outras palavras, basta apenas refenciá-lo para um objeto do tipo Notification:


Notification notificacao = builder.setContentTitle(titulo)
                            .setContentText(mensagem); 
                            .setSmallIcon(R.drawable.casadocodigo) 
                            .build();

Então enviamos o objeto notificacao para o notify():


public void mostrarNotificacao(String mensagem) { 
    String titulo = notification.getTitle(); 
    String mensagem = notification.getBody(); 
    
    NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext()); 
    
    Notification notificacao = builder.setContentTitle(titulo) .setContentText(mensagem); 
    .setSmallIcon(R.drawable.casadocodigo) 
    .build(); 
    
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
    notificationManager.notify(0, notificacao);
}

Testando a nossa App e enviando uma mensagem a partir do firebase, temos o seguinte resultado:

notificacao_sem_acao

Adicionando uma ação na notificação

Ué, por que será que a notificação não faz nada? Um detalhe importante sobre notificações, é que por padrão, elas não possuem ações de clique, portanto, precisamos dar uma ação pra ela!

Geralmente as ações de uma notificação é justamente levar o usuário para uma activity, na maioria dos casos a Launcher da App, nesse caso a MainActivity. Portanto, o nosso primeiro passo é justamente criar uma Intent para essa activity:


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    String titulo = notification.getTitle();
    String mensagem = notification.getBody();
Intent intent = new Intent(this, MainActivity.class);
//restante do código
}

Porém, a classe Notification não possui nenhum método que receba uma Intent... Então como podemos fazer com que a nossa notificação abra essa activity? No Android, temos a classe PadingIntent que além de nos permitir instanciar activities ou services do Android, permite dar uma ação para a notificação. Portanto, vamos implementá-la:


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    String titulo = notification.getTitle(); 
    String mensagem = notification.getBody();
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent .getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

Observe que não instânciamos a PedingIntent na mão, justamente porque ela mesmo já nos fornece instâncias com os seus valores necessários já inicializados. Nesse caso, chamamos o método getActivity() que nos devolve um objeto do tipo PedingIntent que inicializa uma activity. Observe também que já enviamos alguns valores como parâmetro que tem o seguinte significado:

  • 1º parâmetro: Contexto onde será inicializado.
  • 2º parâmetro: refere-se ao request code que é um id para identificar o peding intent dentro da App. (Nesse caso, podemos simplesmente passar qualquer valor).
  • 3º parâmetro: Intent que será executada.
  • 4º parâmetro: Flags que indicam o comportamento do pending intent, nesse exemplo utilizei a constante PendingIntent.FLAG_UPDATE_CURRENT que indica que a peding intent já existe e quero apenas atualizar os dados recebidos pelos extras. (Para mais detalhes das flags consulte a documentação)

Agora que temos o objeto pedingIntent, precisamos apenas settá-lo no objeto notification a partir do método setContentIntent():


NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext()); Notification notificacao = builder.setContentTitle(titulo)           .setContentText(mensagem);
    .setSmallIcon(R.drawable.casadocodigo)
    .setContentIntent(pendingIntent) 
    .build();

Se executarmos novamente a nossa App, temos o seguinte resultado:

notificao_com_acao_mas_nao_sai

Agora a notificação tem uma ação! Nesse caso, ela abre a MainActivity, entretanto, observe que a notificação, mesmo sendo tocada, ainda permanece na barrinha superior do Android! Por que será? Por padrão, quando criamos uma notificação ela só sai da barrinha do Android caso o usuário feche manualmente...

Mas o ideal seria fechar assim que tocar, certo? Será que podemos fazer isso? Sim, podemos! E é mais fácil do que parece, ou seja, basta apenas pedir para o builder que a notificação é auto cancelada assim que tocamos chamando o método setAutoCancel() que recebe um booleano como parâmetro, ou seja, passamos o valor true:


public void mostrarNotificacao(RemoteMessage.Notification notification) { 
    String titulo = notification.getTitle(); 
    String mensagem = notification.getBody();
Intent intent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent .getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Notification notificacao = builder
.setSmallIcon(R.drawable.casadocodigo) 
.setContentTitle(titulo)
.setContentText(mensagem) 
.setContentIntent(pendingIntent) 
.setAutoCancel(true) 
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notificacao);
}

Pronto! Agora temos o mesmo resultado como vimos no início do post. Em outras palavras, estamos recebendo e tratando uma mensagem do FCM em foreground.

Que tal aprender hoje mesmo a desenvolver a sua App Android desde o zero? Na Alura, temos uma formação Android para que você crie sua primeira App com os principais conceitos necessários para desenvolver uma App.

Alex Felipe
Alex Felipe

Alex é instrutor e desenvolvedor e possui experiência em Java, Kotlin, Android. Atualmente cria conteúdo no canal https://www.youtube.com/@AlexFelipeDev.

Veja outros artigos sobre Mobile