Enviar mensagens a vários dispositivos

Há duas maneiras de enviar uma mensagem para vários dispositivos usando o Firebase Cloud Messaging:

  • Mensagens de tópicos, que permitem o envio de uma mensagem a vários dispositivos que optaram por receber mensagens sobre um tópico específico.
  • Mensagens para grupos de dispositivos, que permite o envio de uma só mensagem a vários dispositivos que pertencem a um grupo definido por você.

Este tutorial concentra-se no envio de mensagens de tópicos a partir do servidor de app, usando os protocolos HTTP ou XMPP para o FCM, e no recebimento e processamento dessas mensagens em um app Android. Abordaremos o processamento de mensagens para apps em primeiro e segundo plano. Todas as etapas para alcançar esse objetivo são abordadas, desde a configuração até a verificação.

Configurar o SDK

Se você configurou um app cliente para Android no FCM ou já enviou sua primeira mensagem, talvez as etapas abordadas nesta seção já tenham sido concluídas.

Pré-requisitos

  • Um dispositivo que execute:
    • API nível 16, Jelly Bean, no Android 4.1 ou versão posterior;
    • Google Play Services 15.0.0 ou posterior.
  • A versão mais recente do Android Studio

Se você ainda não tiver um projeto do Android Studio e quiser testar um recurso do Firebase, faça o download de um de nossos exemplos do guia de início rápido. Se você estiver usando o início rápido, anote o código do aplicativo do arquivo build.gradle, que geralmente fica na pasta app/ do módulo do seu project. Você precisará do nome desse pacote na próxima etapa.

Adicionar o Firebase ao app

Adicione o Firebase ao seu app. Para isso, serão necessários um projeto e um arquivo de configuração do Firebase para o app.

Para criar um projeto do Firebase:

  1. Acesse o Console do Firebase.

  2. Clique em Adicionar projeto e selecione ou insira o Nome do projeto.

    • Se você tiver um projeto do Google associado ao seu aplicativo, selecione o projeto no menu suspenso Nome do projeto.
    • Se você não tiver um projeto do Google, insira o novo Nome do projeto.
  3. (Opcional) Edite o código do projeto.

    O Firebase atribui automaticamente um código exclusivo ao seu projeto. Ele é exibido em serviços do Firebase visíveis publicamente, por exemplo:

    • URL padrão do Realtime Database: your-project-id.firebaseio.com
    • Nome padrão do intervalo do Cloud Storage: your-project-id.appspot.com
    • Subdomínio padrão do Hosting: your-project-id.firebaseapp.com
  4. Siga as demais etapas de configuração no Console do Firebase e clique em Criar projeto, ou Adicionar Firebase, se estiver usando um projeto atual do Google.

O Firebase provisiona recursos automaticamente para seu projeto. O processo normalmente leva alguns minutos. Quando o processo for concluído, você será direcionado para a página de visão geral do seu projeto no Console do Firebase.

Agora que você tem um projeto, adicione seu app para Android a ele:

  1. Clique em Adicionar o Firebase ao app para Android e siga as etapas de configuração. Se você estiver importando um projeto do Google, isso poderá ocorrer automaticamente. Basta fazer o download do arquivo de configuração.

  2. Quando solicitado, digite o nome do pacote do app. É importante inserir o nome do pacote usado por seu app. No entanto, essa configuração será feita apenas quando você adicionar um app ao projeto do Firebase.

  3. Para adicionar o arquivo de configuração do Firebase para Android no app, siga estas etapas:

    1. Clique em Fazer o download do google-services.json para receber o arquivo de configuração do Firebase para Android, google-services.json.

      É possível fazer o download do arquivo de configuração do Firebase para Android novamente a qualquer momento.

    2. Mova o arquivo de configuração para o mesmo diretório que o arquivo build.gradle no nível raiz.

  4. Depois de adicionar o código de inicialização, execute seu aplicativo para enviar ao Firebase console a confirmação de que você instalou o Firebase com sucesso.

Adicionar o SDK

Se você quiser integrar as bibliotecas do Firebase a um dos seus projetos, precisará realizar algumas tarefas básicas para preparar o projeto do Android Studio. Talvez você já tenha feito isso quando adicionou o Firebase ao seu app.

Primeiro, adicione regras ao seu arquivo build.gradle no nível raiz para incluir o plug-in google-services e o repositório Maven do Google:

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:4.2.0' // google-services plugin
    }
}

allprojects {
    // ...
    repositories {
        google() // Google's Maven repository
        // ...
    }
}

Em seguida, no arquivo Gradle do módulo (geralmente app/build.gradle), adicione a linha apply plugin na parte inferior do arquivo para ativar o plug-in do Gradle:

apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  implementation 'com.google.firebase:firebase-core:16.0.7'
  implementation 'com.google.firebase:firebase-messaging:17.3.4'
  // Getting a "Could not find" error? Make sure you have
  // added the Google maven respository to your root build.gradle
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

Você também precisa adicionar as dependências dos SDKs do Firebase que quer usar. Recomendamos começar com com.google.firebase:firebase-core, que fornece a funcionalidade do Google Analytics para Firebase. Consulte a lista de bibliotecas disponíveis.

Inscrever o app cliente em um tópico

Os apps cliente podem ser inscritos em qualquer tópico existente ou podem criar um novo tópico. Quando um app cliente for inscrito em um novo nome de tópico que ainda não existe no seu projeto do Firebase, um novo tópico com esse nome será criado no FCM e qualquer cliente poderá se inscrever nele posteriormente.

Para se inscrever em um tópico, o app cliente chama o subscribeToTopic() do Firebase Cloud Messaging com o nome do tópico do FCM. Esse método retorna uma Task, que pode ser usada por um listener de conclusão para determinar se a inscrição foi bem-sucedida:

Java
Android

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                String msg = getString(R.string.msg_subscribed);
                if (!task.isSuccessful()) {
                    msg = getString(R.string.msg_subscribe_failed);
                }
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Kotlin
Android

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener { task ->
            var msg = getString(R.string.msg_subscribed)
            if (!task.isSuccessful) {
                msg = getString(R.string.msg_subscribe_failed)
            }
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        }

Para cancelar a inscrição, o app cliente chama o unsubscribeFromTopic() do Firebase Cloud Messaging com o nome do tópico.

Receber e administrar mensagens de tópico

O FCM entrega as mensagens de tópicos da mesma maneira que as outras mensagens downstream.

Para receber mensagens, use um serviço que estenda FirebaseMessagingService. Seu serviço precisa modificar os 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 de tempo 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, tanto em primeiro quanto 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, você precisa adicionar o seguinte ao manifesto do seu app:

<service android:name=".java.MyFirebaseMessagingService">
    <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 padrão personalizado 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 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
Android

@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 Firebase Job Dispatcher.
            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
Android

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 Firebase Job Dispatcher.
            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 envie uma mensagem. Isso ocorre quando há muitas mensagens pendentes (mais de cem) para o seu app em um dispositivo específico no momento em que ele for 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 de app deve executar uma sincronização completa com o servidor de aplicativos. 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 app 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 não só mensagens que contêm payload de notificação e dados, como todas aquelas enviadas a partir do console do Notifications. Nesses casos, a notificação é entregue à bandeja do sistema do dispositivo, e o payload de dados é entregue nos extras do intent da atividade do inicializador.

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, juntamente com dados de "impressões" (notificações vistas pelos usuários) para apps Android.

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

A partir de janeiro de 2019, o FCM não entregará mensagens para apps que foram definidos com restrição de segundo plano pelo usuário, por exemplo, acessando: Configuração -> Aplicativos 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 esforço Android vitals. Esses comportamentos podem levar o dispositivo Android a recomendar ao usuário que seu app seja restrito em segundo plano. Para que o app verifique se há restrição em segundo plano, use: isBackgroundRestricted ().

Criar solicitações de envio

O envio de mensagens a um tópico do Firebase Cloud Messaging é muito semelhante ao envio a um dispositivo individual ou a um grupo de usuários. O servidor do app define a chave to com um valor como /topics/yourTopic. Os desenvolvedores podem escolher um nome de tópico que corresponda à expressão regular: "/topics/[a-zA-Z0-9-_.~%]+".

Para enviar a combinações de vários tópicos, a chave condition (em vez da chave to) precisa ser definida como uma condição booleana que especifica os tópicos de destino no servidor de apps. Por exemplo, para enviar mensagens para dispositivos que se inscreveram no TopicA e também no TopicB ou TopicC:

'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)

Primeiramente, o FCM avalia todas as condições entre parênteses. Em seguida, ele avalia a expressão da esquerda para a direita. Na expressão acima, um usuário que se inscreveu em um só tópico não receberá a mensagem. Do mesmo modo, um usuário que não se inscreveu no TopicA também não receberá a mensagem. As seguintes combinações receberão a mensagem:

  • TopicA e TopicB
  • TopicA e TopicC

Você pode incluir até cinco tópicos em sua expressão condicional, e parênteses são aceitos. Operadores aceitos: &&, ||, !. Observe o uso para !:

!('TopicA' in topics)

Com essa expressão, todas as instâncias do app que não estão inscritas no TopicA recebem a mensagem, inclusive as que não estão inscritas em nenhum tópico.

Para ver mais detalhes sobre as chaves do servidor do app, consulte as informações de referência do protocolo do servidor de conexão selecionado, HTTP ou XMPP. Veja nesta página exemplos de como enviar mensagens para tópicos nesses protocolos.

Solicitação HTTP POST de tópico

Enviar para um único tópico:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

Enviar para dispositivos inscritos nos tópicos "dogs" ou "cats":

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

Resposta HTTP de tópico

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

Mensagem XMPP de tópico

Enviar para um único tópico:

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

Enviar para dispositivos inscritos nos tópicos "dogs" ou "cats":

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

Resposta XMPP de tópico

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

Aguarde até 30 segundos para que o servidor de conexão do FCM retorne uma resposta de êxito ou falha para as solicitações de envio de tópico. Defina corretamente o valor de tempo limite do servidor de apps na solicitação.

Para ver a lista completa de opções de mensagens, consulte as informações de referência do protocolo do servidor de conexão selecionado (HTTP ou XMPP).

Próximas etapas

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.