如要指定訊息給多部裝置,請使用 主題訊息:這個 功能 傳送訊息給已選擇加入特定主題的多部裝置。
本教學課程著重於使用如何從應用程式伺服器傳送主題訊息: Admin SDK 或 REST API 以接收及處理 FCM 。本頁面將列出從設定到執行的所有步驟 其中可能包含你已完成的步驟 (如果有的話) 為 FCM設定 Apple 用戶端應用程式 或按照傳送第一則訊息的步驟。
將 Firebase 新增至您的 Apple 專案
這個部分涵蓋您已啟用的 還有應用程式適用的其他 Firebase 功能針對 FCM,您應該 需要 上傳 APN 驗證金鑰並 註冊遠端通知。
事前準備
安裝下列項目:
- Xcode 15.2 以上版本
確認專案符合下列規定:
- 您的專案必須指定下列平台版本或更新版本:
- iOS 13
- macOS 10.15
- tvOS 13
- watchOS 7
- 您的專案必須指定下列平台版本或更新版本:
設定實體 Apple 裝置執行應用程式。 並完成以下工作:
- 為您的 Apple 開發人員帳戶。
- 在 [應用程式] 底下的 XCode 中啟用推播通知功能。
如果您沒有 Xcode 專案,只想試用 Firebase 產品,您可以下載其中一個快速入門導覽課程範例。
建立 Firebase 專案
您需要先建立 Firebase,才能將 Firebase 新增到 Apple 應用程式 連線至應用程式前往 如要進一步瞭解 Firebase 專案,請參閱這篇文章 Firebase 專案。
透過 Firebase 註冊應用程式
如要在 Apple 應用程式中使用 Firebase,請向以下應用程式註冊應用程式: Firebase 專案。註冊應用程式通常稱為「新增」將應用程式 專案。
前往 Firebase 控制台。
按一下專案總覽頁面中央的「iOS+」圖示 啟動設定工作流程
如果您已在 Firebase 專案中加入應用程式,請按一下「新增應用程式」 顯示平台選項
在「bundle ID」欄位中輸入應用程式的軟體包 ID。
,瞭解如何調查及移除這項存取權。(選用) 輸入其他應用程式資訊: 「應用程式暱稱」和「App Store ID」。
按一下 [Register app] (註冊應用程式)。
新增 Firebase 設定檔
點選「Download GoogleService-Info.plist」,取得 Firebase Apple 平台設定檔 (
GoogleService-Info.plist
)。將設定檔移至 Xcode 專案的根目錄。如果出現提示訊息 選取即可將設定檔新增至所有目標。
如果專案中有多個軟體包 ID,就必須將每個軟體包建立關聯
與 Firebase 控制台中已註冊應用程式的 ID,讓每個應用程式可擁有
自己的 GoogleService-Info.plist
檔案
在應用程式中新增 Firebase SDK
使用 Swift Package Manager 安裝及管理 Firebase 依附元件。
- 在 Xcode 中保持開啟應用程式專案,然後前往「檔案」檔案 >新增套件。
- 在系統提示時,新增 Firebase Apple 平台 SDK 存放區:
- 選擇 Firebase Cloud Messaging 程式庫。
- 在目標建構設定的「Other Linker Flags」部分中新增
-ObjC
標記。 - 為透過 Firebase Cloud Messaging 獲得最佳體驗,建議你 正在啟用 Google Analytics ,然後將 Google Analytics 專用 Firebase SDK 加進應用程式。你可以 選取沒有收集廣告識別碼 (IDFA) 或收集廣告識別碼的程式庫。
- 完成後,Xcode 會自動開始解析並下載 複製到背景依附元件
https://github.com/firebase/firebase-ios-sdk.git
上傳 APN 驗證金鑰
將 APN 驗證金鑰上傳至 Firebase。 如果您還沒有 APN 驗證金鑰,請務必前往 Apple Developer Member Center。
-
在 Firebase 控制台的專案中,選取 齒輪圖示,選取 「Project Settings」,然後選取 「雲端通訊」分頁。
-
在「iOS 應用程式設定」下方的「APNs 驗證金鑰」中, 按一下「上傳」圖示 按鈕。
-
瀏覽至儲存金鑰的位置並選取金鑰,然後按一下 開啟。加入金鑰的金鑰 ID (位於 Apple Developer Member Center 時,按一下 按一下「上傳」。
在應用程式中初始化 Firebase
您必須將 Firebase 初始化程式碼加進應用程式。匯入 並設定共用執行個體,如下所示:
- 將
FirebaseCore
模組匯入至UIApplicationDelegate
和任何其他 應用程式委派所用的 Firebase 模組。 例如,如要使用 Cloud Firestore 和 Authentication:SwiftUI
import SwiftUI import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Swift
import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
Objective-C
@import FirebaseCore; @import FirebaseFirestore; @import FirebaseAuth; // ...
- 設定
FirebaseApp
敬上 共用執行個體application(_:didFinishLaunchingWithOptions:)
方法:SwiftUI
// Use Firebase library to configure APIs FirebaseApp.configure()
Swift
// Use Firebase library to configure APIs FirebaseApp.configure()
Objective-C
// Use Firebase library to configure APIs [FIRApp configure];
- 如果您使用 SwiftUI,則必須建立並附加應用程式委派
透過
UIApplicationDelegateAdaptor
或App
NSApplicationDelegateAdaptor
。您也必須停用應用程式委派功能切換功能。適用對象 詳情請參閱 SwiftUI 操作說明。SwiftUI
@main struct YourApp: App { // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { NavigationView { ContentView() } } } }
註冊遠端通知
可能是啟動時或應用程式流程中的所需��段。 註冊應用程式以取得遠端通知。致電registerForRemoteNotifications
,如下所示:
Swift
UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: { _, _ in } ) application.registerForRemoteNotifications()
Objective-C
[UNUserNotificationCenter currentNotificationCenter].delegate = self; UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { // ... }]; [application registerForRemoteNotifications];
為用戶端應用程式訂閱主題
用戶端應用程式可以訂閱任何現有的主題,也可以建立新的主題 主題。用戶端應用程式訂閱新的主題名稱時 (具有 Firebase 專案尚不存在的新主題,但這個名稱的新主題會是 在 FCM 中建立,且任何用戶端皆可訂閱其後續服務。
如要訂閱主題,請��叫訂閱方法 呼叫應用程式的主執行緒 (FCM 並非執行緒安全)。 如果訂閱要求一開始失敗,FCM 會自動重試。 無法完成訂閱的情況 訂閱會擲回讓您擷取的錯誤 ,如下所示:
Swift
Messaging.messaging().subscribe(toTopic: "weather") { error in print("Subscribed to weather topic") }
Objective-C
[[FIRMessaging messaging] subscribeToTopic:@"weather" completion:^(NSError * _Nullable error) { NSLog(@"Subscribed to weather topic"); }];
這項呼叫會
並訂閱用戶端給 FCM 後端的非同步要求
指定的主題呼叫 subscribeToTopic:topic
前,請確認
用戶端應用程式執行個體已透過
回呼 didReceiveRegistrationToken
。
每次應用程式啟動時
「FCM」確認已訂閱所有要求的主題。目的地:
取消訂閱、撥打 unsubscribeFromTopic:topic
,
和 FCM 在背景取消訂閱主題。
接收及處理主題訊息
FCM 傳送主題訊息的方式與其他下游方法相同 訊息。
導入application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
如下所示:
Swift
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 }
Objective-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); }
版本傳送要求
建立主題後,您可以透過訂閱用戶端應用程式執行個體 在用戶端或 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
後續步驟
- 您可以使用伺服器,將用戶端應用程式執行個體訂閱至主題,以及 執行其他管理工作詳情請見 管理伺服器上的主題訂閱。