Ir para o console

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 trabalhou para Enviar sua primeira mensagem, talvez as etapas abordadas nesta seção já tenham sido concluídas.

Antes de começar

  • Instale ou atualize o Android Studio para a versão mais recente.

  • Certifique-se de que seu app para Android:

    • segmente o nível 16 da API (Jelly Bean) ou versões posteriores;
    • use o Gradle 4.1 ou versões posteriores.
  • Configure um dispositivo ou emulador para executar seu aplicativo.

    • Emuladores precisam usar uma imagem de emulador no Google Play.
  • Faça login no Firebase usando sua Conta do Google.

Se você ainda não tiver um projeto de app para Android e quiser testar um produto do Firebase, faça o download de um dos nossos exemplos para início rápido.

Criar um projeto do Firebase

Antes de adicionar o Firebase ao seu projeto de app para Android, é preciso criar um projeto do Firebase para ser conectado ao seu projeto de app para Android. Para mais informações, consulte Noções básicas sobre projetos do Firebase.

Registre seu app com o Firebase

Depois de ter um projeto do Firebase, é possível adicionar seu app para Android a ele.

Consulte Noções básicas sobre projetos do Firebase para ver práticas recomendadas e informações sobre como adicionar apps a um projeto, incluindo como lidar com diversas variantes de criação.

  1. No centro da página de visão geral do projeto do console do Firebase, clique no ícone Android para iniciar o fluxo de trabalho de configuração.

    Se você já adicionou um aplicativo ao seu projeto do Firebase, clique em Adicionar app para exibir as opções da plataforma.

  2. Insira o ID do aplicativo no campo Nome do pacote do Android.

    • Às vezes, um ID do aplicativo é chamado de nome do pacote.

    • Esse ID do aplicativo é encontrado no arquivo Gradle do seu módulo (nível do app), geralmente app/build.gradle (exemplo de ID: com.yourcompany.yourproject).

  3. (Opcional) Insira outras informações do app conforme solicitado pelo fluxo de trabalho de configuração.

    O apelido é um identificador interno de conveniência e só é visível no Console do Firebase.

  4. Clique em Registrar aplicativo.

Adicionar um arquivo de configuração do Firebase

  1. 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 Android (google-services.json).

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

    2. Mova seu arquivo de configuração para o diretório (nível do app) do seu aplicativo.

  2. Para ativar os produtos do Firebase no seu app, adicione o plug-in google-services aos seus arquivos do Gradle.

    1. No nível raiz (nível do projeto) do seu arquivo Gradle (build.gradle), adicione regras para incluir o plug-in do Google Services. Verifique se você tem o repositório Maven do Google também.

      buildscript {
      
        repositories {
          // Check that you have the following line (if not, add it):
          google()  // Google's Maven repository
        }
      
        dependencies {
          // ...
      
          // Add the following line:
          classpath 'com.google.gms:google-services:4.2.0'  // Google Services plugin
        }
      }
      
      allprojects {
        // ...
      
        repositories {
          // Check that you have the following line (if not, add it):
          google()  // Google's Maven repository
          // ...
        }
      }
      
    2. No arquivo Gradle do seu módulo (nível do app) (geralmente app/build.gradle), adicione a seguinte linha no fim do arquivo.

      apply plugin: 'com.android.application'
      
      android {
        // ...
      }
      
      // Add the following line to the bottom of the file:
      apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin
      

Adicionar SDKs do Firebase ao seu app

É possível adicionar qualquer um dos produtos do Firebase compatíveis ao seu app para Android. Recomendamos começar com o SDK básico do Firebase (com.google.firebase:firebase-core), que oferece a funcionalidade do Google Analytics para Firebase.

  1. No seu arquivo Gradle do módulo (nível do app), geralmente app/build.gradle, adicione a dependência do SDK básico do Firebase:

    dependencies {
     // ...
     implementation 'com.google.firebase:firebase-core:16.0.9'
    
     // Getting a "Could not find" error? Make sure that you've added
     // Google's Maven repository to your root-level build.gradle file
    }
    
  2. (Opcional) Adicione as dependências para as outras bibliotecas do Firebase que você deseja usar.

    Alguns SDKs do Firebase para Android oferecem uma biblioteca alternativa de extensões do Kotlin.

  3. Sincronize seu app para garantir que todas as dependências tenham as versões necessárias.

  4. Execute seu app para enviar ao Firebase a confirmação de que você integrou o Firebase com sucesso.

    Os registros do dispositivo exibirão a verificação do Firebase de que a inicialização foi concluída. Se você executou seu app em um emulador com acesso à rede, o Console do Firebase notifica que a conexão do seu app está completa.

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

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

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ópico da mesma maneira que as outras mensagens downstream.

Para receber mensagens, use um serviço que amplie FirebaseMessagingService. Seu serviço precisa modificar 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 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"
    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 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

@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

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 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 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 do inicializador.

Para ver insights sobre a entrega de mensagens para 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 recurso 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

Depois de criar um tópico, seja inscrevendo instâncias do app cliente para o tópico no cliente ou por meio da API do servidor, será possível enviar mensagens a ele. Na sua lógica de envio no back-end, especifique o nome do tópico desejado conforme mostrado abaixo:

Node.js

// The topic name can be optionally prefixed with "/topics/".
var topic = 'highScores';

var message = {
  data: {
    score: '850',
    time: '2:45'
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
admin.messaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";

// See documentation on defining a message payload.
Message message = Message.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .setTopic(topic)
    .build();

// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

Python

# The topic name can be optionally prefixed with "/topics/".
topic = 'highScores'

# See documentation on defining a message payload.
message = messaging.Message(
    data={
        'score': '850',
        'time': '2:45',
    },
    topic=topic,
)

# Send a message to the devices subscribed to the provided topic.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// The topic name can be optionally prefixed with "/topics/".
topic := "highScores"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Topic: topic,
}

// Send a message to the devices subscribed to the provided topic.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// The topic name can be optionally prefixed with "/topics/".
var topic = "highScores";

// See documentation on defining a message payload.
var message = new Message()
{
    Data = new Dictionary<string, string>()
    {
        { "score", "850" },
        { "time", "2:45" },
    },
    Topic = topic,
};

// Send a message to the devices subscribed to the provided topic.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
  "message":{
    "topic" : "foo-bar",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message"
      }
   }
}

Comando cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "message": {
    "topic" : "foo-bar",
    "notification": {
      "body": "This is a Firebase Cloud Messaging Topic Message!",
      "title": "FCM Message"
    }
  }
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Para enviar uma mensagem para uma combinação de tópicos, especifique uma condição, que é uma expressão booleana que especifica os tópicos de destino. Por exemplo, a seguinte condição enviará mensagens para dispositivos que estão inscritos em TopicA e em TopicB ou TopicC:

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

No FCM, todas as condições entre parênteses são avaliadas primeiro e depois a expressão é analisada 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 em TopicA também não receberá a mensagem. Somente estas combinações são válidas:

  • TopicA e TopicB
  • TopicA e TopicC

É possível incluir até cinco tópicos na sua expressão condicional.

Para enviar para uma condição:

Node.js

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
var condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
var message = {
  notification: {
    title: '$GOOG up 1.43% on the day',
    body: '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.'
  },
  condition: condition
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
admin.messaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
String condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
Message message = Message.builder()
    .setNotification(new Notification(
        "$GOOG up 1.43% on the day",
        "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day."))
    .setCondition(condition)
    .build();

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

Python

# Define a condition which will send to devices which are subscribed
# to either the Google stock or the tech industry topics.
condition = "'stock-GOOG' in topics || 'industry-tech' in topics"

# See documentation on defining a message payload.
message = messaging.Message(
    notification=messaging.Notification(
        title='$GOOG up 1.43% on the day',
        body='$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',
    ),
    condition=condition,
)

# Send a message to devices subscribed to the combination of topics
# specified by the provided condition.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Condition: condition,
}

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
var condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
var message = new Message()
{
    Notification = new Notification()
    {
        Title = "$GOOG up 1.43% on the day",
        Body = "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
    },
    Condition = condition,
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
   "message":{
    "condition": "'dogs' in topics || 'cats' in topics",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message",
    }
  }
}

Comando cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "notification": {
    "title": "FCM Message",
    "body": "This is a Firebase Cloud Messaging Topic Message!",
  },
  "condition": "'dogs' in topics || 'cats' in topics"
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Próximas etapas