FCM 的主題訊息功能依發布/訂閱模式而異,方便你傳送訊息 使用者只要選擇在多部裝置上放送特定主題,廣告就會受到影響。您撰寫主題訊息的方式為 而 FCM 可穩定地將訊息轉送至 裝置。
例如:當地新娘的使用者 預測應用程式可選擇接收「潮時差快訊」主題並接收 關於指定區域最佳海水釣魚情況的通知。運動應用程式的使用者 可以訂閱自己喜愛的即時賽事比分自動更新 團隊。
使用主題時,請注意下列事項:
- 主題訊息最適合用於天氣或其他公開內容 可用的資訊
- 主題訊息針對處理量進行最佳化,而非延遲時間。快速且安全,將貨物運送至 或一小組裝置 將訊息傳送至註冊權杖 而不是主題
- 如需「依使用者」傳送訊息給多部裝置,建議您 裝置群組訊息 適合這些用途
- 每個主題的訊息功能支援無限次訂閱。但 FCM
在這些方面施行限制:
- 每個應用程式執行個體最多只能訂閱 2000 個主題。
- 如果使用 批次匯入 訂閱應用程式執行個體,則每個要求最多只能有 1, 000 個應用程式執行個體。
- 每項專案的新增訂閱頻率都設有頻率限制。如果傳送過多
短時間內的訂閱要求,FCM 伺服器會回應
429 RESOURCE_EXHAUSTED
(「超過配額」) 回應。使用以下應用程式重試: 指數輪詢。
為用戶端應用程式訂閱主題
用戶端應用程式可以訂閱任何現有的主題,也可以建立新的主題 主題。用戶端應用程式訂閱新的主題名稱時 (具有 Firebase 專案尚不存在的新主題,但這個名稱的新主題會是 任何透過 FCM 建立且任何客戶都能訂閱的。
為了訂閱主題,用戶端應用程式會呼叫 Firebase 雲端通訊
將 subscribeToTopic()
替換為 FCM 主題名稱。這個方法
會傳回 Task
,完成事件監聽器可用於判斷
訂閱成功:
Kotlin+KTX
Firebase.messaging.subscribeToTopic("weather") .addOnCompleteListener { task -> var msg = "Subscribed" if (!task.isSuccessful) { msg = "Subscribe failed" } Log.d(TAG, msg) Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() }
Java
FirebaseMessaging.getInstance().subscribeToTopic("weather") .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { String msg = "Subscribed"; if (!task.isSuccessful()) { msg = "Subscribe failed"; } Log.d(TAG, msg); Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); } });
如要取消訂閱,用戶端應用程式會呼叫 Firebase 雲端通訊 unsubscribeFromTopic()
替換成主題名稱
管理伺服器上的主題訂閱
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 傳送主題訊息的方式與其他下游方法相同 訊息。
如要接收訊息,請使用
FirebaseMessagingService
。
您的服務應覆寫 onMessageReceived
和 onDeletedMessages
回呼函式。
郵件處理時長可能短於 20 秒,視延遲情況而定
在呼叫 onMessageReceived
之前發生,包括 OS 延遲、應用程式啟動時間、
主要執行緒遭到其他作業封鎖 (或先前的 onMessageReceived
)
通話時間過長。超過 190 天後,各種作業系統行為,如 Android 的
處理程序
終止或 Android O 的
背景執行限制可能會影響無法完成工作。
大多數訊息類型都會提供 onMessageReceived
,包含以下內容
例外狀況:
-
應用程式在背景執行時顯示的通知訊息。在本 案例,通知會傳送到裝置的系統匣。使用者輕觸通知 預設開啟應用程式啟動器。
-
在背景接收時,具有通知和資料酬載的訊息。 在此情況下,通知會傳送到裝置的系統匣。 而資料酬載則會在 啟動器活動的意圖。
簡單來說:
應用程式狀態 | 通知 | 資料 | 兩者並用 |
---|---|---|---|
前景 | onMessageReceived |
onMessageReceived |
onMessageReceived |
背景 | 系統匣 | onMessageReceived |
通知:系統匣 資料:就意圖的額外資料。 |
編輯應用程式資訊清單
若要使用 FirebaseMessagingService
,您必須在
應用程式資訊清單:
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
此外,建議您設定預設值,自訂通知的外觀。個人中心 可以指定自訂預設圖示以及自訂預設顏色, 並不會在通知酬載中設定對等的值。
在
application
標記來設定自訂預設圖示和自訂顏色:
<!-- 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" />
Android 會顯示自訂預設圖示
- 透過以下服務傳送的所有通知訊息: 通知編輯器。
- 未明確設定通知酬載中圖示的任何通知訊息。
Android 會使用自訂預設顏色
- 透過以下服務傳送的所有通知訊息: 通知編輯器。
- 未明確設定通知顏色的任何通知訊息 酬載。
如未設定自訂預設圖示,也未在通知酬載中設定圖示, Android 顯示應用程式圖示以白色顯示。
覆寫 onMessageReceived
覆寫 FirebaseMessagingService.onMessageReceived
方法後
您就能依據
RemoteMessage
物件,並取得訊息資料:
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. if (remoteMessage.data.isNotEmpty()) { Log.d(TAG, "Message data payload: ${remoteMessage.data}") // Check if data needs to be processed by long running job if (needsToBeScheduled()) { // 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. }
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. }
覆寫 onDeletedMessages
在某些情況下,FCM 可能無法傳送訊息,當系統傳送過多提案時
有 則訊息 (>100) 待審核
應用程式在連線的特定裝置上,或裝置未連線時
已有超過 1 個月啟用 FCM。在這些情況下
系統可能會回撥給 FirebaseMessagingService.onDeletedMessages()
應用程式執行個體收到此回呼時
應該能與應用程式伺服器執行完整同步。如果有沒有傳送訊息給應用程式
裝置在過去 4 週內,FCM 將不會呼叫 onDeletedMessages()
。
在背景執行應用程式中處理通知訊息
當應用程式在背景運作時,Android 會將通知訊息導向至 系統匣。使用者輕觸通知,即可開啟應用程式啟動器 預設值。
這包括包含通知和資料的訊息 酬載 (以及從通知控制台傳送的所有郵件)。 在這些情況下,通知會傳送到裝置的 系統匣,而資料酬載則會在意圖的額外項目中傳送 。
如要進一步瞭解訊息傳送至應用程式的資訊,請參閱 FCM 報表資訊主頁,其中記錄 透過 Apple 和 Android 裝置傳送及開啟的訊息數量,以及 「曝光」資料Android 應用程式 (使用者看到的通知)。
版本傳送要求
建立主題後,您可以透過訂閱用戶端應用程式執行個體 在用戶端或 server 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
後續步驟
- 進一步瞭解傳送到多部裝置的其他方式。 裝置群組訊息