Receber mensagens em um app Android

O serviço Firebase Notificações se comporta de maneira diferente dependendo do estado em primeiro/segundo plano do app de destino. Se você quer que apps em primeiro plano recebam mensagens de notificação ou de dados, escreva o código para processar a callback onMessageReceived. Veja uma explicação sobre a diferença entre as mensagens de notificação e de dados em Tipos de mensagem.

Como processar mensagens

Para receber mensagens, use um serviço que amplie o FirebaseMessagingService. Seu serviço precisa substituir as callbacks onMessageReceived e onDeletedMessages. Ele deve processar qualquer mensagem em até 20 segundos após o recebimento (10 segundos no Android Marshmallow). O período pode ser mais curto, dependendo dos atrasos do SO incorridos antes de chamar onMessageReceived. Depois disso, vários comportamentos do SO, como os limites de execução em segundo plano do Android O, podem interferir na capacidade de concluir seu trabalho. Para mais informações, consulte nossa visão geral sobre prioridade de mensagens.

O onMessageReceived está disponível para a maioria dos tipos de mensagens, com as seguintes exceções:

  • Mensagens de notificação entregues quando seu app estiver em segundo plano. Nesse caso, a notificação é entregue à bandeja do sistema do dispositivo. Quando um usuário toca na notificação, a tela de início do app é aberta por padrão.

  • Mensagens com payload de notificação e dados, quando recebidas em segundo plano. Nesse caso, a notificação é entregue à bandeja do sistema do dispositivo, e o payload de dados é entregue nos extras da intent da atividade da sua tela de início.

Em resumo:

Estado do app Notificação Dados Ambos
Primeiro plano onMessageReceived onMessageReceived onMessageReceived
Segundo plano Bandeja do sistema onMessageReceived Notificação: bandeja do sistema
Dados: nos extras da intent.
Para mais informações sobre os tipos de mensagens, consulte Notificações e mensagens de dados.

Editar o manifesto do app

Para usar FirebaseMessagingService, adicione o seguinte ao manifesto do seu app:

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Além disso, recomendamos que você defina valores padrão para personalizar a aparência das notificações. É possível especificar uma cor e um ícone padrão personalizados que serão aplicados sempre que valores equivalentes não estiverem definidos no payload da notificação.

Adicione estas linhas na tag application para definir a cor e o ícone padrão personalizados:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

O Android exibe o ícone personalizado padrão para:

  • todas as mensagens de notificação enviadas pelo Editor do Notificações;
  • todas as mensagens de notificação que não definem explicitamente o ícone no payload da notificação.

O Android usa a cor padrão personalizada para:

  • todas as mensagens de notificação enviadas pelo Editor do Notificações;
  • todas as mensagens de notificação que não definem explicitamente a cor no payload de notificação.

Se não houver um ícone personalizado padrão ou nenhum ícone estiver definido no payload de notificação, o Android exibirá o ícone do aplicativo renderizado na cor branca.

Substituir onMessageReceived

Ao substituir o método FirebaseMessagingService.onMessageReceived, é possível realizar ações com base no objeto RemoteMessage recebido e acessar os dados da mensagem:

Kotlin+KTX

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob()
        } else {
            // Handle message within 10 seconds
            handleNow()
        }
    }

    // Check if message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Substituir onDeletedMessages

Em algumas situações, é possível que o FCM não entregue uma mensagem. Isso ocorre quando há muitas mensagens pendentes (mais de 100) no app em um dispositivo específico no momento em que ele é conectado ou se o dispositivo não for conectado ao FCM por mais de um mês. Nesses casos, talvez você receba uma callback para FirebaseMessagingService.onDeletedMessages(). Quando isso acontece, a instância do app precisa executar uma sincronização completa com o servidor do app. Se você não enviou uma mensagem ao app no dispositivo nas últimas quatro semanas, o FCM não vai chamar onDeletedMessages().

Processar mensagens de notificação em um app em segundo plano

Quando seu app está em segundo plano, o Android direciona as notificações para a bandeja do sistema. Quando um usuário toca nelas, a tela de início do aplicativo é aberta por padrão.

Isso inclui mensagens que contêm payload de notificação e dados, assim como todas aquelas enviadas pelo console do Notificações. Nesses casos, a notificação é entregue à bandeja do sistema do dispositivo, e o payload de dados é entregue nos extras da intent da atividade da tela de início.

Confira as informações sobre a entrega de mensagens ao seu app no painel de relatórios do FCM, que registra o número de mensagens enviadas e abertas em dispositivos Apple e Android, além de dados de "impressões" (notificações vistas pelos usuários) para apps Android.

Receber mensagens do FCM no modo de inicialização direta

Os desenvolvedores que quiserem enviar mensagens do FCM para apps antes mesmo do dispositivo ser desbloqueado poderão permitir que um app para Android receba mensagens quando o dispositivo estiver no modo de inicialização direta. Por exemplo, talvez você queira que os usuários do seu app recebam notificações de alarme mesmo em um dispositivo bloqueado.

Ao criar esse caso de uso, observe as práticas recomendadas e restrições gerais para o modo de inicialização direta. É especialmente importante considerar a visibilidade das mensagens enviadas na inicialização direta. Qualquer usuário com acesso ao dispositivo poderá ver essas mensagens sem digitar as credenciais do usuário.

Pré-requisitos

  • O dispositivo precisa estar configurado para o modo de inicialização direta.
  • O dispositivo precisa ter uma versão recente do Google Play Services instalada (19.0.54 ou superior).
  • O app precisa usar o SDK do FCM (com.google.firebase:firebase-messaging) para receber mensagens do FCM.

Ativar o gerenciamento de mensagens no modo de inicialização direta no seu app

  1. No arquivo Gradle no nível do app, adicione uma dependência à biblioteca de suporte da inicialização direta do FCM:

    implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
    
  2. Adicione o atributo android:directBootAware="true" ao manifesto do app para fazer FirebaseMessagingService funcionar na inicialização direta:

    <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false"
        android:directBootAware="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    

É importante garantir que FirebaseMessagingService possa ser executado no modo de inicialização direta. Verifique os seguintes requisitos:

  • O serviço não deve acessar o armazenamento protegido por credenciais durante a execução no modo de inicialização direta.
  • O serviço não deve tentar usar componentes, como Activities, BroadcastReceivers ou outros Services que não estão marcados para funcionar no modo de inicialização direta.
  • Todas as bibliotecas que o serviço usar também não poderão acessar o armazenamento protegido por credenciais nem chamar componentes non-directBootAware durante a execução no modo de inicialização direta. Isso significa que todas as bibliotecas que o app usa e que são chamadas usando o serviço precisam estar marcadas para funcionar na inicialização direta ou o app deve verificar se ele está em execução no modo de inicialização direta para não chamar as bibliotecas se esse for o caso. Por exemplo, os SDKs do Firebase funcionam com a inicialização direta (eles podem ser incluídos em um app sem causar falhas nesse modo), mas muitas APIs do Firebase não são compatíveis com a inicialização direta.
  • Se o app está usando um Application personalizado, o Application também precisa estar marcado para funcionar na inicialização direta (sem acesso ao armazenamento protegido por credenciais no modo de inicialização direta).

Para ver como enviar mensagens para dispositivos no modo de inicialização direta, consulte este link.