根據發布/訂閱模式,FCM主題訊息可讓您將訊息傳送至已選擇特定主題的多部裝置。您可以視需要撰寫主題訊息,FCM 會負責將訊息轉送並可靠地傳送至正確的裝置。
舉例來說,當地潮汐預報應用程式的使用者可以選擇加入「潮汐流警報」主題,並接收指定區域內最佳海水釣魚條件的通知。體育應用程式使用者可以訂閱喜愛球隊的賽事比分自動更新通知。
主題注意事項:
- 主題訊息最適合用於天氣或其他公開資訊等內容。
- 主題訊息是針對總處理量進行最佳化調整,而非針對延遲。如要快速安全地將訊息傳送至單一裝置或小型裝置群組,請將訊息目標指定為註冊權杖,而非主題。
- 如要為每位使用者傳送訊息至多部裝置,請考慮在這些用途中使用 裝置群組訊息。
- 主題訊息傳送功能支援每個主題的無限訂閱項目。不過,FCM 會強制執行下列限制:
- 一個應用程式執行個體最多可訂閱 2000 個主題。
- 如果您使用批次匯入訂閱應用程式執行個體,每個要求最多只能包含 1, 000 個應用程式執行個體。
- 每個專案的新訂閱頻率都有速率限制。如果在短時間內傳送過多訂閱要求,FCM 伺服器會傳回
429 RESOURCE_EXHAUSTED
(「超過配額」) 回應。以指數輪詢方式重試。
讓用戶端應用程式訂閱主題
如要訂閱主題,請從應用程式呼叫 ::firebase::messaging::Subscribe
。這會對 FCM 後端發出非同步要求,並讓用戶端訂閱指定主題。
::firebase::messaging::Subscribe("example");
如果訂閱要求一開始失敗,FCM 會重試,直到成功訂閱主題為止。應用程式每次啟動時,FCM 都會確保已訂閱所有要求的訊息主題。
如要取消訂閱,請呼叫 ::firebase::messaging::Unsubscribe
,FCM 會在背景取消訂閱主題。
在伺服器上管理主題訂閱項目
Firebase Admin SDK 可讓您從伺服器端執行基本主題管理工作。您可以使用伺服器邏輯,根據註冊權杖大量訂閱及取消訂閱用戶端應用程式執行個體。
您可以讓用戶端應用程式執行個體訂閱任何現有主題,也可以建立新主題。使用 API 將用戶端應用程式訂閱至新主題 (Firebase 專案中尚未存在的主題) 時,系統會在 FCM 中建立該名稱的新主題,之後任何用戶端都能訂閱該主題。
您可以將註冊權杖清單傳遞至 Firebase Admin SDK 訂閱方法,讓對應裝置訂閱主題:
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");
Python
# 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')
Go
// 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");
您也可以透過 Admin FCM API,將註冊權杖傳遞至適當的方法,取消訂閱裝置的主題:
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");
Python
# 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')
Go
// 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");
subscribeToTopic()
和 unsubscribeFromTopic()
方法會產生物件,其中包含 FCM 的回應。無論要求中指定的註冊權杖數量為何,傳回型別的格式都相同。
如果發生錯誤 (驗證失敗、權杖或主題無效等),這些方法會導致錯誤。如需錯誤代碼的完整清單 (包括說明和解決步驟),請參閱「Admin FCM API 錯誤」。
接收及處理主題訊息
FCM 傳送主題訊息的方式與其他下游訊息相同。
覆寫 ::firebase::messaging::Listener::OnMessage
方法,即可根據收到的訊息執行動作,並取得訊息資料:
void OnMessage(const ::firebase::messaging::Message& message) { LogMessage(TAG, "From: %s", message.from.c_str()); LogMessage(TAG, "Message ID: %s", message.message_id.c_str()); }
建立傳送要求
建立主題後,您可以透過用戶端訂閱主題,或使用伺服器 API,然後傳送訊息至該主題。如果您是第一次為 FCM 建立傳送要求,請參閱伺服器環境和 FCM 的指南,瞭解重要的背景和設定資訊。
在後端的傳送邏輯中,指定所需的主題名稱,如下所示:
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);
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" } } }
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
如要將訊息傳送至主題組合,請指定條件,也就是指定目標主題的布林運算式。舉例來說,下列條件會將訊息傳送至已訂閱 TopicA
,且訂閱 TopicB
或 TopicC
的裝置:
"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"
FCM 會先評估括號中的任何條件,然後從左到右評估運算式。在上述運算式中,訂閱任何單一主題的使用者都不會收到訊息。同樣地,如果使用者未訂閱 TopicA
,就不會收到訊息。以下組合會收到這項資訊:
TopicA
和TopicB
TopicA
和TopicC
條件式運算式最多可包含五個主題。
如要傳送至條件:
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);
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", } } }
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