Artigos de Tecnologia e Negócios > Mobile

Tratando notificações recebidas do Firebase no Android

Alex Felipe
Alex Felipe

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.

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`, é 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:

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:

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:

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.

Artigos de Tecnologia e Negócios > Mobile