Receber mensagens em um app para Android

O Firebase Notificações se comporta de maneira diferente, dependendo do estado em primeiro/segundo plano do app receptor. Se você quiser que apps em primeiro plano recebam mensagens de notificação ou de dados, você vai precisar escrever código para lidar com o retorno de chamada onMessageReceived. Veja uma explicação sobre a diferença entre as mensagens de notificação e de dados em Tipos de mensagem.

Lidar com mensagens

Para receber mensagens, use um serviço que amplie o FirebaseMessagingService. Seu serviço precisa substituir os retornos de chamada 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 do 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 do 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 personalizada 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 a cor no payload de notificação.

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

Modificar onMessageReceived

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

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.
}

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.
    remoteMessage.data.isNotEmpty().let {
        Log.d(TAG, "Message data payload: " + remoteMessage.data)

        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.
    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.
}

Modificar onDeletedMessages

Em algumas situações, é possível que o FCM não entregue uma mensagem. Isso ocorre quando há muitas mensagens pendentes (mais de cem) para seu 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, é possível que você receba um retorno de chamada para FirebaseMessagingService.onDeletedMessages(). Ao receber esse retorno de chamada, a instância do app deve executar uma sincronização completa com o servidor do aplicativo. Se você não enviou uma mensagem ao app no dispositivo nas últimas quatro semanas, o FCM não chamará onDeletedMessages().

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

Quando seu aplicativo 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 a partir do console do Notificações. Nesses casos, a notificação é entregue à bandeja do sistema do dispositivo, e o payload de dados é entregue nos extras do intent da atividade da tela de início.

Para ver insights sobre a entrega de mensagens ao seu aplicativo, consulte o painel de relatórios do FCM, que registra o número de mensagens enviadas e abertas em dispositivos iOS e Android, além de dados de impressões (notificações vistas pelos usuários) para apps Android.

Apps restritos em segundo plano (Android P ou mais recente)

O FCM não pode entregar mensagens a apps que foram colocados em restrições em segundo plano pelo usuário (por exemplo, Configurações -> Apps e Notificação -> [nome do app] -> Bateria). Depois que seu app for removido da restrição de segundo plano, novas mensagens serão exibidas como antes. Para evitar a perda de mensagens e outros impactos da restrição de segundo plano, evite os maus comportamentos listados pelo recurso Android vitals. Esses comportamentos podem levar o dispositivo Android a recomendar ao usuário que seu app seja restringido em segundo plano. Para que o app verifique se há restrição em segundo plano, use: isBackgroundRestricted().

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 superiores).
  • 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 [serviços], 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 deverá 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 estiver usando um Application personalizado, o Application também precisará estar marcado para funcionar na inicialização direta (sem acesso ao armazenamento protegido por credenciais nesse modo).

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