您可以使用 Firebase Admin SDK 或 FCM 應用程式伺服器通訊協定,建立訊息要求並傳送至下列類型的目標:
- 主題名稱
- 條件
- 裝置註冊權杖
- 裝置群組名稱 (僅限通訊協定)
您可以傳送含有通知酬載的訊息,該酬載由預先定義的欄位組成,也可以傳送含有您自行定義欄位資料酬載的訊息,或者傳送含有這兩種酬載的訊息。詳情請參閱 訊息類型。
本頁中的範例說明如何使用 Firebase Admin SDK (支援 Node、Java、Python、C# 和 Go) 和 v1 HTTP 通訊協定傳送通知訊息。
傳送訊息至特定裝置
如要傳送至單一特定裝置,請如圖所示傳遞裝置的註冊權杖。請參閱平台的用戶端設定資訊,進一步瞭解註冊權杖。
// This registration token comes from the client FCM SDKs.
const registrationToken = 'YOUR_REGISTRATION_TOKEN';
const message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
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);
});
// This registration token comes from the client FCM SDKs.
String registrationToken = "YOUR_REGISTRATION_TOKEN";
// See documentation on defining a message payload.
Message message = Message.builder()
.putData("score", "850")
.putData("time", "2:45")
.setToken(registrationToken)
.build();
// Send a message to the device corresponding to the provided
// registration token.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);
# This registration token comes from the client FCM SDKs.
registration_token = 'YOUR_REGISTRATION_TOKEN'
# See documentation on defining a message payload.
message = messaging.Message(
data={
'score': '850',
'time': '2:45',
},
token=registration_token,
)
# Send a message to the device corresponding to the provided
# registration token.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)
// Obtain a messaging.Client from the App.
ctx := context.Background()
client, err := app.Messaging(ctx)
if err != nil {
log.Fatalf("error getting Messaging client: %v\n", err)
}
// This registration token comes from the client FCM SDKs.
registrationToken := "YOUR_REGISTRATION_TOKEN"
// See documentation on defining a message payload.
message := &messaging.Message{
Data: map[string]string{
"score": "850",
"time": "2:45",
},
Token: registrationToken,
}
// Send a message to the device corresponding to the provided
// registration token.
response, err := client.Send(ctx, message)
if err != nil {
log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)
// This registration token comes from the client FCM SDKs.
var registrationToken = "YOUR_REGISTRATION_TOKEN";
// See documentation on defining a message payload.
var message = new Message()
{
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
Token = registrationToken,
};
// Send a message to the device corresponding to the provided
// registration token.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);
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":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"body":"This is an FCM notification message!",
"title":"FCM Message"
}
}
}
cURL 指令:
curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
"message":{
"notification":{
"title":"FCM Message",
"body":"This is an FCM Message"
},
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send
傳送成功後,每個傳送方法都會傳回訊息 ID。Firebase Admin SDK 會以 projects/{project_id}/messages/{message_id}
格式傳回 ID 字串。HTTP 通訊協定回應是單一 JSON 鍵:
{
"name":"projects/myproject-b5ae1/messages/0:1500415314455276%31bd1c9631bd1c96"
}
將訊息傳送至多部裝置
您可以使用管理員 FCM API 將訊息多播至裝置註冊權杖清單。每次叫用最多可指定 500 個裝置註冊權杖。
// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// …
'YOUR_REGISTRATION_TOKEN_N',
];
const message = {
data: {score: '850', time: '2:45'},
tokens: registrationTokens,
};
getMessaging().sendMulticast(message)
.then((response) => {
console.log(response.successCount + ' messages were sent successfully');
});
// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n"
);
MulticastMessage message = MulticastMessage.builder()
.putData("score", "850")
.putData("time", "2:45")
.addAllTokens(registrationTokens)
.build();
BatchResponse response = FirebaseMessaging.getInstance().sendMulticast(message);
// See the BatchResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " messages were sent successfully");
# Create a list containing up to 500 registration tokens.
# These registration tokens come from the client FCM SDKs.
registration_tokens = [
'YOUR_REGISTRATION_TOKEN_1',
# ...
'YOUR_REGISTRATION_TOKEN_N',
]
message = messaging.MulticastMessage(
data={'score': '850', 'time': '2:45'},
tokens=registration_tokens,
)
response = messaging.send_multicast(message)
# See the BatchResponse reference documentation
# for the contents of response.
print('{0} messages were sent successfully'.format(response.success_count))
// Create a list containing up to 500 registration tokens.
// This registration tokens come from the client FCM SDKs.
registrationTokens := []string{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
}
message := &messaging.MulticastMessage{
Data: map[string]string{
"score": "850",
"time": "2:45",
},
Tokens: registrationTokens,
}
br, err := client.SendMulticast(context.Background(), message)
if err != nil {
log.Fatalln(err)
}
// See the BatchResponse reference documentation
// for the contents of response.
fmt.Printf("%d messages were sent successfully\n", br.SuccessCount)
// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
};
var message = new MulticastMessage()
{
Tokens = registrationTokens,
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
};
var response = await FirebaseMessaging.DefaultInstance.SendEachForMulticastAsync(message);
// See the BatchResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} messages were sent successfully");
傳回值是符記清單,對應於輸入符記的順序。如要檢查哪些符記導致錯誤,這項功能就非常實用。
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// …
'YOUR_REGISTRATION_TOKEN_N',
];
const message = {
data: {score: '850', time: '2:45'},
tokens: registrationTokens,
};
getMessaging().sendMulticast(message)
.then((response) => {
if (response.failureCount > 0) {
const failedTokens = [];
response.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(registrationTokens[idx]);
}
});
console.log('List of tokens that caused failures: ' + failedTokens);
}
});
// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n"
);
MulticastMessage message = MulticastMessage.builder()
.putData("score", "850")
.putData("time", "2:45")
.addAllTokens(registrationTokens)
.build();
BatchResponse response = FirebaseMessaging.getInstance().sendMulticast(message);
if (response.getFailureCount() > 0) {
List<SendResponse> responses = response.getResponses();
List<String> failedTokens = new ArrayList<>();
for (int i = 0; i < responses.size(); i++) {
if (!responses.get(i).isSuccessful()) {
// The order of responses corresponds to the order of the registration tokens.
failedTokens.add(registrationTokens.get(i));
}
}
System.out.println("List of tokens that caused failures: " + failedTokens);
}
# These registration tokens come from the client FCM SDKs.
registration_tokens = [
'YOUR_REGISTRATION_TOKEN_1',
# ...
'YOUR_REGISTRATION_TOKEN_N',
]
message = messaging.MulticastMessage(
data={'score': '850', 'time': '2:45'},
tokens=registration_tokens,
)
response = messaging.send_multicast(message)
if response.failure_count > 0:
responses = response.responses
failed_tokens = []
for idx, resp in enumerate(responses):
if not resp.success:
# The order of responses corresponds to the order of the registration tokens.
failed_tokens.append(registration_tokens[idx])
print('List of tokens that caused failures: {0}'.format(failed_tokens))
// Create a list containing up to 500 registration tokens.
// This registration tokens come from the client FCM SDKs.
registrationTokens := []string{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
}
message := &messaging.MulticastMessage{
Data: map[string]string{
"score": "850",
"time": "2:45",
},
Tokens: registrationTokens,
}
br, err := client.SendMulticast(context.Background(), message)
if err != nil {
log.Fatalln(err)
}
if br.FailureCount > 0 {
var failedTokens []string
for idx, resp := range br.Responses {
if !resp.Success {
// The order of responses corresponds to the order of the registration tokens.
failedTokens = append(failedTokens, registrationTokens[idx])
}
}
fmt.Printf("List of tokens that caused failures: %v\n", failedTokens)
}
// These registration tokens come from the client FCM SDKs.
var registrationTokens = new List<string>()
{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
};
var message = new MulticastMessage()
{
Tokens = registrationTokens,
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
};
var response = await FirebaseMessaging.DefaultInstance.SendEachForMulticastAsync(message);
if (response.FailureCount > 0)
{
var failedTokens = new List<string>();
for (var i = 0; i < response.Responses.Count; i++)
{
if (!response.Responses[i].IsSuccess)
{
// The order of responses corresponds to the order of the registration tokens.
failedTokens.Add(registrationTokens[i]);
}
}
Console.WriteLine($"List of tokens that caused failures: {failedTokens}");
}
將訊息發送至主題
建立主題後,您可以透過訂閱用戶端應用程式執行個體,或透過伺服器 API,將訊息傳送至主題。如果這是您首次為 FCM 建立傳送要求,請參閱伺服器環境和 FCM 指南,瞭解重要背景資訊和設定資訊。
在後端的傳送邏輯中,指定所需的專案名稱,如下所示:
// 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);
});
// 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);
# 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)
// 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)
// 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);
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
您最多可以在條件式運算式中加入五個主題。
如要傳送至條件:
// 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);
});
// 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);
# 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)
// 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)
// 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);
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
傳送訊息至裝置群組
如要傳送訊息給裝置群組,請使用 HTTP v1 API。如果您目前使用已淘汰的舊版 HTTP 或 XMPP 傳送 API,或任何舊版 Firebase Admin SDK for Node.js,以舊版通訊協定傳送至裝置群組,強烈建議您盡快遷移至 HTTP v1 API。舊版傳送 API 將於 2024 年 6 月停用及移除。
傳送訊息給裝置群組與傳送訊息給個別裝置非常相似,兩者都使用相同的方法授權傳送要求。將 token
欄位設為群組通知索引鍵:
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":{
"token":"APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ",
"data":{
"hello": "This is a Firebase Cloud Messaging device group message!"
}
}
}
curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
"message":{
"data":{
"hello": "This is a Firebase Cloud Messaging device group message!"
},
"token":"APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ"
}}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send
傳送一批訊息
管理員 SDK 支援以批次傳送訊息。您可以將最多 500 則訊息分組成單一批次,然後在單一 API 呼叫中傳送這些訊息,這樣比針對每則訊息傳送個別 HTTP 要求,可大幅提升效能。
這項功能可用於建立自訂訊息組合,並將這些訊息傳送給不同的收件者,包括主題或特定裝置註冊權杖。例如,如果您需要同時傳送訊息給不同目標對象,且訊息內文的詳細資料略有不同,就可以使用這項功能。
// Create a list containing up to 500 messages.
const messages = [];
messages.push({
notification: { title: 'Price drop', body: '5% off all electronics' },
token: registrationToken,
});
messages.push({
notification: { title: 'Price drop', body: '2% off all books' },
topic: 'readers-club',
});
getMessaging().sendAll(messages)
.then((response) => {
console.log(response.successCount + ' messages were sent successfully');
});
// Create a list containing up to 500 messages.
List<Message> messages = Arrays.asList(
Message.builder()
.setNotification(Notification.builder()
.setTitle("Price drop")
.setBody("5% off all electronics")
.build())
.setToken(registrationToken)
.build(),
// ...
Message.builder()
.setNotification(Notification.builder()
.setTitle("Price drop")
.setBody("2% off all books")
.build())
.setTopic("readers-club")
.build()
);
BatchResponse response = FirebaseMessaging.getInstance().sendAll(messages);
// See the BatchResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " messages were sent successfully");
# Create a list containing up to 500 messages.
messages = [
messaging.Message(
notification=messaging.Notification('Price drop', '5% off all electronics'),
token=registration_token,
),
# ...
messaging.Message(
notification=messaging.Notification('Price drop', '2% off all books'),
topic='readers-club',
),
]
response = messaging.send_all(messages)
# See the BatchResponse reference documentation
# for the contents of response.
print('{0} messages were sent successfully'.format(response.success_count))
// Create a list containing up to 500 messages.
messages := []*messaging.Message{
{
Notification: &messaging.Notification{
Title: "Price drop",
Body: "5% off all electronics",
},
Token: registrationToken,
},
{
Notification: &messaging.Notification{
Title: "Price drop",
Body: "2% off all books",
},
Topic: "readers-club",
},
}
br, err := client.SendAll(context.Background(), messages)
if err != nil {
log.Fatalln(err)
}
// See the BatchResponse reference documentation
// for the contents of response.
fmt.Printf("%d messages were sent successfully\n", br.SuccessCount)
// Create a list containing up to 500 messages.
var messages = new List<Message>()
{
new Message()
{
Notification = new Notification()
{
Title = "Price drop",
Body = "5% off all electronics",
},
Token = registrationToken,
},
new Message()
{
Notification = new Notification()
{
Title = "Price drop",
Body = "2% off all books",
},
Topic = "readers-club",
},
};
var response = await FirebaseMessaging.DefaultInstance.SendEachAsync(messages);
// See the BatchResponse reference documentation
// for the contents of response.
Console.WriteLine($"{response.SuccessCount} messages were sent successfully");
傳送啟用直接啟動的訊息 (僅限 Android)
您可以使用 HTTP v1 或舊版 HTTP API,將訊息傳送至直接啟動模式的裝置。在傳送至直接啟動模式的裝置之前,請先完成步驟,讓用戶端裝置在直接啟動模式下接收 FCM 訊息。
使用 FCM v1 HTTP API 傳送
訊息要求必須在要求主體的 AndroidConfig
選項中加入 "direct_boot_ok" : true
鍵。例如:
https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send
Content-Type:application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message":{
"token" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
"data": {
"score": "5x1",
"time": "15:10"
},
"android": {
"direct_boot_ok": true,
},
}
跨平台自訂訊息
Firebase Admin SDK 和 FCM v1 HTTP 通訊協定都允許訊息要求設定 message
物件中可用的所有欄位。包括:
- 一組常見的欄位,可供所有接收訊息的應用程式執行個體解讀。
- 特定平台的欄位組合 (例如
AndroidConfig
和WebpushConfig
),僅由在指定平台上執行的應用程式執行個體解讀。
您可以靈活運用平台專屬區塊,為不同平台自訂訊息,確保訊息在收到時能正確處理。FCM 後端會考量所有指定參數,並為各平台自訂訊息。
使用常用欄位的時機
使用常用欄位時,請注意:
- 指定所有平台 (Apple、Android 和網站) 上的應用程式執行個體
- 將訊息傳送至主題
無論平台為何,所有應用程式例項都能解讀下列常見欄位:
使用平台專屬欄位的時機
請在下列情況下使用平台專屬欄位:
- 只將欄位傳送至特定平台
- 除了一般欄位外,也傳送特定平台欄位
如要只將值傳送至特定平台,請不要使用通用欄位,請使用特定平台的欄位。舉例來說,如果您想只將通知傳送給 Apple 平台和網頁,而非 Android,就必須使用兩組不同的欄位,一組用於 Apple,另一組用於網頁。
傳送含有特定傳送選項的郵件時,請使用特定平台的欄位進行設定。您可以視需要為每個平台指定不同的值。不過,即使您想在各平台上設定相同的值,也必須使用平台專屬欄位。這是因為每個平台對這個值的解讀方式略有不同。舉例來說,Android 將生命週期設為以秒為單位的到期時間,而 Apple 則將生命週期設為到期日期。
範例:含有顏色和圖示選項的通知訊息
這個範例傳送要求會將常見的通知標題和內容傳送至所有平台,但也會將某些平台專屬的覆寫值傳送至 Android 裝置。
針對 Android,請求會設定在 Android 裝置上顯示的特殊圖示和顏色。如 AndroidNotification 參考資料所述,顏色會以 #rrggbb 格式指定,且圖片必須是 Android 應用程式本機的繪製可用圖示資源。
以下是使用者裝置上大致的視覺效果:
const topicName = 'industry-tech';
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.'
},
android: {
notification: {
icon: 'stock_ticker_update',
color: '#7e55c3'
}
},
topic: topicName,
};
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);
});
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())
.setAndroidConfig(AndroidConfig.builder()
.setTtl(3600 * 1000)
.setNotification(AndroidNotification.builder()
.setIcon("stock_ticker_update")
.setColor("#f45342")
.build())
.build())
.setApnsConfig(ApnsConfig.builder()
.setAps(Aps.builder()
.setBadge(42)
.build())
.build())
.setTopic("industry-tech")
.build();
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.',
),
android=messaging.AndroidConfig(
ttl=datetime.timedelta(seconds=3600),
priority='normal',
notification=messaging.AndroidNotification(
icon='stock_ticker_update',
color='#f45342'
),
),
apns=messaging.APNSConfig(
payload=messaging.APNSPayload(
aps=messaging.Aps(badge=42),
),
),
topic='industry-tech',
)
oneHour := time.Duration(1) * time.Hour
badge := 42
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.",
},
Android: &messaging.AndroidConfig{
TTL: &oneHour,
Notification: &messaging.AndroidNotification{
Icon: "stock_ticker_update",
Color: "#f45342",
},
},
APNS: &messaging.APNSConfig{
Payload: &messaging.APNSPayload{
Aps: &messaging.Aps{
Badge: &badge,
},
},
},
Topic: "industry-tech",
}
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.",
},
Android = new AndroidConfig()
{
TimeToLive = TimeSpan.FromHours(1),
Notification = new AndroidNotification()
{
Icon = "stock_ticker_update",
Color = "#f45342",
},
},
Apns = new ApnsConfig()
{
Aps = new Aps()
{
Badge = 42,
},
},
Topic = "industry-tech",
};
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":"industry-tech",
"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."
},
"android":{
"notification":{
"icon":"stock_ticker_update",
"color":"#7e55c3"
}
}
}
}
如要進一步瞭解訊息主體中特定平台區塊可用的鍵,請參閱 HTTP v1 參考說明文件。
範例:含有自訂圖片的通知訊息
以下範例傳送要求會將常見的通知標題傳送至所有平台,但也會傳送圖片。以下是使用者裝置上視覺效果的近似效果:
const topicName = 'industry-tech';
const message = {
notification: {
title: 'Sparky says hello!'
},
android: {
notification: {
imageUrl: 'https://foo.bar.pizza-monster.png'
}
},
apns: {
payload: {
aps: {
'mutable-content': 1
}
},
fcm_options: {
image: 'https://foo.bar.pizza-monster.png'
}
},
webpush: {
headers: {
image: 'https://foo.bar.pizza-monster.png'
}
},
topic: topicName,
};
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);
});
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":"industry-tech",
"notification":{
"title":"Sparky says hello!",
},
"android":{
"notification":{
"image":"https://foo.bar/pizza-monster.png"
}
},
"apns":{
"payload":{
"aps":{
"mutable-content":1
}
},
"fcm_options": {
"image":"https://foo.bar/pizza-monster.png"
}
},
"webpush":{
"headers":{
"image":"https://foo.bar/pizza-monster.png"
}
}
}
}
如要進一步瞭解訊息主體中特定平台區塊可用的鍵,請參閱 HTTP v1 參考說明文件。
範例:含有相關點擊動作的通知訊息
下列範例傳送要求會將常見的通知標題傳送至所有平台,但也會傳送動作,讓應用程式在使用者與通知互動時做出回應。以下是使用者裝置上大致的視覺效果:
const topicName = 'industry-tech';
const message = {
notification: {
title: 'Breaking News....'
},
android: {
notification: {
clickAction: 'news_intent'
}
},
apns: {
payload: {
aps: {
'category': 'INVITE_CATEGORY'
}
}
},
webpush: {
fcmOptions: {
link: 'breakingnews.html'
}
},
topic: topicName,
};
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);
});
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":"industry-tech",
"notification":{
"title":"Breaking News...",
},
"android":{
"notification":{
"click_action":"news_intent"
}
},
"apns":{
"payload":{
"aps":{
"category" : "INVITE_CATEGORY"
}
},
},
"webpush":{
"fcm_options":{
"link":"breakingnews.html"
}
}
}
}
如要進一步瞭解訊息主體中特定平台區塊可用的鍵,請參閱 HTTP v1 參考說明文件。
範例:含有本地化選項的通知訊息
以下範例傳送要求會傳送本地化選項,讓用戶端顯示本地化訊息。以下是使用者裝置上的視覺效果:
var topicName = 'industry-tech';
var message = {
android: {
ttl: 3600000,
notification: {
bodyLocKey: 'STOCK_NOTIFICATION_BODY',
bodyLocArgs: ['FooCorp', '11.80', '835.67', '1.43']
}
},
apns: {
payload: {
aps: {
alert: {
locKey: 'STOCK_NOTIFICATION_BODY',
locArgs: ['FooCorp', '11.80', '835.67', '1.43']
}
}
}
},
topic: topicName,
};
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);
});
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":"Tech",
"android":{
"ttl":"3600s",
"notification":{
"body_loc_key": "STOCK_NOTIFICATION_BODY",
"body_loc_args": ["FooCorp", "11.80", "835.67", "1.43"],
},
},
"apns":{
"payload":{
"aps":{
"alert" : {
"loc-key": "STOCK_NOTIFICATION_BODY",
"loc-args": ["FooCorp", "11.80", "835.67", "1.43"],
},
},
},
},
},
}'
如要進一步瞭解訊息主體中特定平台區塊可用的鍵,請參閱 HTTP v1 參考說明文件。
HTTP v1 API 的 REST 錯誤代碼
HTTP v1 API 的 HTTP 錯誤回應包含錯誤代碼、錯誤訊息和錯誤狀態。這些資料也可能包含 details
陣列,其中包含更多錯誤詳細資料。
以下是兩個錯誤回應範例:
範例 1:HTTP v1 API 要求的錯誤回應,資料訊息中包含無效值
{
"error": {
"code": 400,
"message": "Invalid value at 'message.data[0].value' (TYPE_STRING), 12",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "message.data[0].value",
"description": "Invalid value at 'message.data[0].value' (TYPE_STRING), 12"
}
]
}
]
}
}
範例 2:使用無效的註冊權杖,透過 HTTP v1 API 要求傳送的錯誤回應
{
"error": {
"code": 400,
"message": "The registration token is not a valid FCM registration token",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode": "INVALID_ARGUMENT"
}
]
}
}
請注意,兩則訊息的代碼和狀態相同,但詳細資料陣列包含不同類型的值。第一個範例的類型為 type.googleapis.com/google.rpc.BadRequest
,表示要求值有誤。第二個範例的類型為 type.googleapis.com/google.firebase.fcm.v1.FcmError
,有 FCM 專屬錯誤。對於許多錯誤,詳細資料陣列會包含偵錯和找出解決方案所需的資訊。
下表列出 FCM v1 REST API 錯誤代碼和說明。
錯誤代碼 | 說明和解決步驟 |
---|---|
UNSPECIFIED_ERROR 我們無法提供更多有關此錯誤的資訊。 |
無 |
INVALID_ARGUMENT (HTTP 錯誤代碼 = 400) 要求參數無效。系統會傳回 google.rpc.BadRequest 類型的擴充功能,以指定哪個欄位無效。 |
可能的原因包括無效的註冊、無效的套件名稱、訊息過大、無效的資料鍵、無效的 TTL 或其他無效的參數。 無效的註冊:請檢查您傳遞至伺服器的註冊權杖格式。請確認該權杖與用戶端應用程式透過 FCM 註冊時收到的註冊權杖相符。請勿截斷符記或新增其他字元。 套件名稱無效:請確認訊息已傳送至註冊權杖,且該權杖的套件名稱與要求中傳遞的值相符。 訊息過大:請確認訊息中包含的酬載資料總大小未超過 FCM 限制:大多數訊息為 4096 位元組,針對主題的訊息則為 2048 位元組。包括鍵和值。 無效的資料鍵:請確認酬載資料不含 FCM 內部使用的鍵 (例如 from、gcm 或任何前面有 google 字樣的值)。請注意,FCM 也會使用部分字詞 (例如 collapse_key),但這些字詞在酬載中是允許的,在這種情況下,酬載值會被 FCM 值覆寫。 無效的 TTL:請確認在 ttl 中使用的值為整數,代表的時間長度為 0 到 2,419,200 秒 (4 週) 之間。 無效的參數:請確認提供的參數名稱和類型正確無誤。 |
UNREGISTERED (HTTP 錯誤代碼 = 404) 應用程式執行個體已從 FCM 取消註冊。這通常表示所使用的權杖已失效,必須使用新的權杖。 |
這個錯誤可能是因為缺少註冊權杖,或是未註冊的權杖。 未註冊:如果訊息的目標是 token 值,請確認要求包含註冊權杖。未註冊:在許多情況下,現有的註冊權杖可能會失效,包括: - 如果用戶端應用程式取消註冊 FCM。 - 如果用戶解除安裝應用程式,系統就會自動取消註冊用戶端應用程式。舉例來說,如果在 iOS 上,APNs 意見回饋服務回報 APNs 權杖無效。 - 如果註冊權杖到期 (例如 Google 可能決定重新整理註冊權杖,或是 iOS 裝置的 APN 權杖到期)。 - 如果用戶端應用程式已更新,但新版本未設定為接收訊息。 在上述所有情況下,請從應用程式伺服器中移除此註冊權杖,並停止使用該權杖傳送訊息。 |
SENDER_ID_MISMATCH (HTTP 錯誤代碼 = 403) 已驗證的寄件者 ID 與註冊權杖的寄件者 ID 不同。 |
註冊權杖會與特定一組寄件者相關聯。當用戶端應用程式註冊 FCM 時,必須指定哪些傳送者可以傳送訊息。傳送訊息至用戶端應用程式時,請使用其中一個傳送者 ID。如果切換至其他傳送者,現有的註冊權杖將無法運作。 |
QUOTA_EXCEEDED (HTTP 錯誤代碼 = 429) 已超過郵件目標的傳送限制。系統會傳回 google.rpc.QuotaFailure 類型的擴充資料,以指定超出哪個配額。 |
這可能因為超出訊息傳送率配額、裝置訊息傳送率配額或主題訊息傳送率配額而發生。 訊息傳送頻率超出上限:訊息傳送頻率過高。您必須降低傳送訊息的整體頻率。使用指數輪詢,並設定最小初始延遲時間為 1 分鐘,以便重試遭拒絕的訊息。 裝置訊息傳送頻率超出上限:傳送至特定裝置的訊息頻率過高。請參閱「單一裝置的訊息傳送速率限制」。請減少傳送至此裝置的訊息數量,並使用指數輪詢重試傳送。 主題訊息比率超出上限:向特定主題訂閱者的訊息比率過高。減少為這個主題傳送的訊息數量,並使用指數輪詢,以 1 分鐘的初始延遲時間重試傳送。 |
UNAVAILABLE (HTTP 錯誤代碼 = 503) 伺服器超載。 |
伺服器無法及時處理要求。重試相同要求,但您必須: - 如果 FCM 連線伺服器的回應中包含 Retry-After 標頭,請遵循該標頭。 - 在重試機制中實作指數輪詢。(例如,如果您在第一次重試前等待一秒,請在下次重試前等待至少兩秒,然後是 4 秒,依此類推)。如果您傳送多則訊息,建議您採用抖動技術。詳情請參閱「處理重試」。造成問題的寄件者可能會遭到拒絕。 |
INTERNAL (HTTP 錯誤代碼 = 500) 發生不明的內部錯誤。 |
伺服器在處理要求時發生錯誤,您可以按照「處理重試」一節中的建議,重試相同要求。如果錯誤持續發生,請與 Firebase 支援團隊聯絡。 |
THIRD_PARTY_AUTH_ERROR (HTTP 錯誤代碼 = 401) APNs 憑證或網路推播驗證金鑰無效或遺失。 |
無法傳送指定 iOS 裝置的訊息或網頁推送註冊。檢查開發和實際運作環境的憑證是否有效。 |
管理員錯誤代碼
下表列出 Firebase Admin FCM API 錯誤代碼和說明,以及建議的解決步驟。
錯誤代碼 | 說明和解決步驟 |
---|---|
messaging/invalid-argument |
提供給 FCM 方法的引數無效。錯誤訊息應包含其他資訊。 |
messaging/invalid-recipient |
指定的訊息收件者無效。錯誤訊息應包含其他資訊。 |
messaging/invalid-payload |
提供的訊息酬載物件無效。錯誤訊息應包含其他資訊。 |
messaging/invalid-data-payload-key |
資料訊息酬載包含無效的鍵。如要瞭解受限制的金鑰,請參閱
DataMessagePayload 的參考說明文件。 |
messaging/payload-size-limit-exceeded |
提供的訊息酬載超過 FCM 大小限制。大多數訊息的限制為 4096 個位元組。傳送至主題的訊息上限為 2048 個位元組。總酬載大小包含鍵和值。 |
messaging/invalid-options |
提供的訊息選項物件無效。錯誤訊息應包含其他資訊。 |
messaging/invalid-registration-token |
提供的註冊權杖無效。請確認該值與用戶端應用程式透過 FCM 註冊所收到的註冊權杖相符。請勿截斷或新增其他字元。 |
messaging/registration-token-not-registered |
提供的註冊權杖未註冊。先前有效的註冊權杖可能會因各種原因而取消註冊,包括:
|
messaging/invalid-package-name |
這則訊息是傳送給註冊權杖,但該權杖的套件名稱與提供的
restrictedPackageName 選項不符。 |
messaging/message-rate-exceeded |
傳送給特定目標的訊息比率過高。請減少傳送至此裝置或主題的訊息數量,並不要立即嘗試傳送至這個目標。 |
messaging/device-message-rate-exceeded |
傳送至特定裝置的訊息比率過高。請減少傳送至這部裝置的訊息數量,並不要立即嘗試傳送至這部裝置。 |
messaging/topics-message-rate-exceeded |
向特定主題訂閱者的訊息比率過高。 減少為這個主題傳送的訊息數量,並且不要立即重試傳送至這個主題。 |
messaging/too-many-topics |
註冊權杖已訂閱的話題數量已達上限,無法再訂閱其他話題。 |
messaging/invalid-apns-credentials |
由於未上傳必要的 APNs SSL 憑證或憑證已過期,因此無法傳送指定 Apple 裝置的訊息。檢查開發和正式版憑證的有效性。 |
messaging/mismatched-credential |
用於驗證此 SDK 的憑證沒有權限將訊息傳送至對應於所提供註冊權杖的裝置。請確認憑證和註冊權杖都屬於同一個 Firebase 專案。如要瞭解如何驗證 Firebase Admin SDK,請參閱「將 Firebase 新增至應用程式」一文。 |
messaging/authentication-error |
SDK 無法向 FCM 伺服器進行驗證。請務必使用具備適當權限 (可傳送 FCM 訊息) 的憑證,驗證 Firebase Admin SDK。如要瞭解如何驗證 Firebase Admin SDK,請參閱「將 Firebase 新增至應用程式」一文。 |
messaging/server-unavailable |
FCM 伺服器無法及時處理要求。您應重試相同要求,但必須:
|
messaging/internal-error |
FCM 伺服器在處理要求時發生錯誤。您可以按照上述 messaging/server-unavailable 列中列出的規定,重試相同要求。如果錯誤仍未解決,請向我們的錯誤報告支援管道回報問題。 |
messaging/unknown-error |
傳回不明的伺服器錯誤。如需更多詳細資料,請參閱錯誤訊息中的原始伺服器回應。如果您收到這則錯誤訊息,請將完整的錯誤訊息回報給我們的錯誤報告支援管道。 |