Com base no modelo de publicação/assinatura, as mensagens de tópico do FCM permitem enviar uma mensagem para vários dispositivos que aceitaram um tópico específico. Você redige mensagens de tópico conforme necessário e o FCM cuida do roteamento e da entrega da mensagem de maneira confiável aos dispositivos certos.
Por exemplo, os usuários de um aplicativo local de previsão de marés podem optar por um tópico de “alertas de correntes de maré” e receber notificações sobre condições ideais de pesca em água salgada em áreas específicas. Os usuários de um aplicativo de esportes podem assinar atualizações automáticas de resultados de jogos ao vivo de seus times favoritos.
Algumas coisas para ter em mente sobre os tópicos:
- As mensagens de tópico são mais adequadas para conteúdos como previsão do tempo ou outras informações disponíveis publicamente.
- As mensagens do tópico são otimizadas para rendimento em vez de latência . Para uma entrega rápida e segura para dispositivos únicos ou pequenos grupos de dispositivos, direcione as mensagens para tokens de registro e não para tópicos.
- Se você precisar enviar mensagens para vários dispositivos por usuário , considere enviar mensagens de grupo de dispositivos para esses casos de uso.
- As mensagens de tópico oferecem suporte a assinaturas ilimitadas para cada tópico. No entanto, a FCM impõe limites nestas áreas:
- Uma instância de aplicativo não pode ser inscrita em mais de 2.000 tópicos.
- Se você estiver usando a importação em lote para assinar instâncias de aplicativos, cada solicitação será limitada a 1.000 instâncias de aplicativos.
- A frequência de novas assinaturas é limitada por taxa por projeto. Se você enviar muitas solicitações de assinatura em um curto período de tempo, os servidores FCM responderão com uma resposta
429 RESOURCE_EXHAUSTED
("cota excedida"). Tente novamente com espera exponencial.
Inscrever o aplicativo cliente em um tópico
Os aplicativos cliente podem assinar qualquer tópico existente ou podem criar um novo tópico. Quando um aplicativo cliente assina um novo nome de tópico (um que ainda não existe para seu projeto do Firebase), um novo tópico com esse nome é criado no FCM e qualquer cliente pode subscrevê-lo posteriormente.
Para assinar um tópico, chame o método de assinatura do thread principal do seu aplicativo (FCM não é thread-safe). Se a solicitação de assinatura falhar inicialmente, o FCM tentará novamente automaticamente. Para casos em que a assinatura não pode ser concluída, a assinatura gera um erro que pode ser detectado em um manipulador de conclusão, conforme mostrado:
Rápido
Messaging.messaging().subscribe(toTopic: "weather") { error in print("Subscribed to weather topic") }
Objetivo-C
[[FIRMessaging messaging] subscribeToTopic:@"weather" completion:^(NSError * _Nullable error) { NSLog(@"Subscribed to weather topic"); }];
Esta chamada faz uma solicitação assíncrona ao back-end do FCM e inscreve o cliente no tópico determinado. Antes de chamar subscribeToTopic:topic
, certifique-se de que a instância do aplicativo cliente já recebeu um token de registro por meio do retorno de chamada didReceiveRegistrationToken
.
Cada vez que o aplicativo é iniciado, o FCM garante que todos os tópicos solicitados foram inscritos. Para cancelar a assinatura, chame unsubscribeFromTopic:topic
e o FCM cancelará a assinatura do tópico em segundo plano.
Gerenciar assinaturas de tópicos no servidor
O SDK Admin do Firebase permite executar tarefas básicas de gerenciamento de tópicos no lado do servidor. Dados os tokens de registro, você pode assinar e cancelar a assinatura de instâncias de aplicativos cliente em massa usando a lógica do servidor.
Você pode inscrever instâncias de aplicativos clientes em qualquer tópico existente ou criar um novo tópico. Quando você usa a API para inscrever um aplicativo cliente em um novo tópico (um que ainda não existe para seu projeto do Firebase), um novo tópico com esse nome é criado no FCM e qualquer cliente pode subscrevê-lo posteriormente.
Você pode transmitir uma lista de tokens de registro ao método de assinatura do Firebase Admin SDK para inscrever os dispositivos correspondentes em um tópico:
Node.js
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// ...
'YOUR_REGISTRATION_TOKEN_n'
];
// Subscribe the devices corresponding to the registration tokens to the
// topic.
getMessaging().subscribeToTopic(registrationTokens, topic)
.then((response) => {
// See the MessagingTopicManagementResponse reference documentation
// for the contents of response.
console.log('Successfully subscribed to topic:', response);
})
.catch((error) => {
console.log('Error subscribing to topic:', error);
});
Java
// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n"
);
// Subscribe the devices corresponding to the registration tokens to the
// topic.
TopicManagementResponse response = FirebaseMessaging.getInstance().subscribeToTopic(
registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " tokens were subscribed successfully");
Pitão
# These registration tokens come from the client FCM SDKs.
registration_tokens = [
'YOUR_REGISTRATION_TOKEN_1',
# ...
'YOUR_REGISTRATION_TOKEN_n',
]
# Subscribe the devices corresponding to the registration tokens to the
# topic.
response = messaging.subscribe_to_topic(registration_tokens, topic)
# See the TopicManagementResponse reference documentation
# for the contents of response.
print(response.success_count, 'tokens were subscribed successfully')
Ir
// These registration tokens come from the client FCM SDKs.
registrationTokens := []string{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
}
// Subscribe the devices corresponding to the registration tokens to the
// topic.
response, err := client.SubscribeToTopic(ctx, registrationTokens, topic)
if err != nil {
log.Fatalln(err)
}
// See the TopicManagementResponse reference documentation
// for the contents of response.
fmt.Println(response.SuccessCount, "tokens were subscribed successfully")
C#
// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
};
// Subscribe the devices corresponding to the registration tokens to the
// topic
var response = await FirebaseMessaging.DefaultInstance.SubscribeToTopicAsync(
registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} tokens were subscribed successfully");
A API Admin FCM também permite cancelar a assinatura de dispositivos de um tópico, passando tokens de registro para o método apropriado:
Node.js
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// ...
'YOUR_REGISTRATION_TOKEN_n'
];
// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
getMessaging().unsubscribeFromTopic(registrationTokens, topic)
.then((response) => {
// See the MessagingTopicManagementResponse reference documentation
// for the contents of response.
console.log('Successfully unsubscribed from topic:', response);
})
.catch((error) => {
console.log('Error unsubscribing from topic:', error);
});
Java
// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n"
);
// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
TopicManagementResponse response = FirebaseMessaging.getInstance().unsubscribeFromTopic(
registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " tokens were unsubscribed successfully");
Pitão
# These registration tokens come from the client FCM SDKs.
registration_tokens = [
'YOUR_REGISTRATION_TOKEN_1',
# ...
'YOUR_REGISTRATION_TOKEN_n',
]
# Unubscribe the devices corresponding to the registration tokens from the
# topic.
response = messaging.unsubscribe_from_topic(registration_tokens, topic)
# See the TopicManagementResponse reference documentation
# for the contents of response.
print(response.success_count, 'tokens were unsubscribed successfully')
Ir
// These registration tokens come from the client FCM SDKs.
registrationTokens := []string{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
}
// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
response, err := client.UnsubscribeFromTopic(ctx, registrationTokens, topic)
if err != nil {
log.Fatalln(err)
}
// See the TopicManagementResponse reference documentation
// for the contents of response.
fmt.Println(response.SuccessCount, "tokens were unsubscribed successfully")
C#
// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
};
// Unsubscribe the devices corresponding to the registration tokens from the
// topic
var response = await FirebaseMessaging.DefaultInstance.UnsubscribeFromTopicAsync(
registrationTokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} tokens were unsubscribed successfully");
Os métodos subscribeToTopic()
e unsubscribeFromTopic()
resultam em um objeto contendo a resposta do FCM. O tipo de retorno possui o mesmo formato, independentemente do número de tokens de registro especificado na solicitação.
Em caso de erro (falhas de autenticação, token ou tópico inválido, etc.) esses métodos resultam em erro. Para obter uma lista completa de códigos de erro, incluindo descrições e etapas de resolução, consulte Erros da API Admin FCM .
Receber e lidar com mensagens de tópico
O FCM entrega mensagens de tópico da mesma forma que outras mensagens downstream.
Implemente application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
conforme mostrado:
Rápido
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) async -> UIBackgroundFetchResult { // If you are receiving a notification message while your app is in the background, // this callback will not be fired till the user taps on the notification launching the application. // TODO: Handle data of notification // With swizzling disabled you must let Messaging know about the message, for Analytics // Messaging.messaging().appDidReceiveMessage(userInfo) // Print message ID. if let messageID = userInfo[gcmMessageIDKey] { print("Message ID: \(messageID)") } // Print full message. print(userInfo) return UIBackgroundFetchResult.newData }
Objetivo-C
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // If you are receiving a notification message while your app is in the background, // this callback will not be fired till the user taps on the notification launching the application. // TODO: Handle data of notification // With swizzling disabled you must let Messaging know about the message, for Analytics // [[FIRMessaging messaging] appDidReceiveMessage:userInfo]; // ... // Print full message. NSLog(@"%@", userInfo); completionHandler(UIBackgroundFetchResultNewData); }
Crie solicitações de envio
Depois de criar um tópico, seja inscrevendo instâncias do aplicativo cliente no tópico no lado do cliente ou por meio da API do servidor , você poderá enviar mensagens para o tópico. Se esta for a primeira vez que você cria solicitações de envio para o FCM, consulte o guia do ambiente do seu servidor e do FCM para obter informações importantes sobre antecedentes e configuração.
Na sua lógica de envio no backend, especifique o nome do tópico desejado conforme mostrado:
Node.js
// The topic name can be optionally prefixed with "/topics/".
const topic = 'highScores';
const message = {
data: {
score: '850',
time: '2:45'
},
topic: topic
};
// Send a message to devices subscribed to the provided topic.
getMessaging().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);
Pitão
# 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)
Ir
// 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);
DESCANSAR
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 condição a seguir enviará mensagens para dispositivos inscritos em TopicA
e TopicB
ou TopicC
:
"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"
O FCM primeiro avalia quaisquer condições entre parênteses e depois avalia a expressão da esquerda para a direita. Na expressão acima, um usuário inscrito em um único tópico não recebe a mensagem. Da mesma forma, um usuário que não assina o TopicA
não recebe a mensagem. Estas combinações recebem:
-
TopicA
eTopicB
-
TopicA
eTopicC
Você pode incluir até cinco tópicos em 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.
const condition = '\'stock-GOOG\' in topics || \'industry-tech\' in topics';
// See documentation on defining a message payload.
const message = {
notification: {
title: '$FooCorp up 1.43% on the day',
body: '$FooCorp 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.
getMessaging().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(Notification.builder()
.setTitle("$GOOG up 1.43% on the day")
.setBody("$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.")
.build())
.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);
Pitão
# 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)
Ir
// 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);
DESCANSAR
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óximos passos
- Saiba mais sobre outra maneira de enviar para vários dispositivos: mensagens de grupo de dispositivos