如要將訊息傳送至多部裝置,請使用主題訊息。這項功能可讓您將訊息傳送至已選擇特定主題的多部裝置。
本教學課程著重於使用 FCM 的 Admin SDK 或 REST API,從應用程式伺服器傳送主題訊息,並在 Apple 應用程式中接收及處理這些訊息。本頁面列出所有步驟,從設定到驗證都有,因此如果您已設定 Apple 用戶端應用程式以使用 FCM,或已完成傳送第一則訊息的步驟,可能已完成部分步驟。
將 Firebase 新增至 Apple 專案
如果您已為應用程式啟用其他 Firebase 功能,可能已完成本節所述工作。不過,如要使用 FCM,您需要上傳 APN 驗證金鑰,並註冊遠端通知。
事前準備
安裝下列項目:
- Xcode 16.2 以上版本
請確認專案符合下列規定:
- 專案必須以這些平台版本或更新版本為目標:
- iOS 13
- macOS 10.15
- tvOS 13
- watchOS 7
- 專案必須以這些平台版本或更新版本為目標:
設定實體 Apple 裝置來執行應用程式,並完成下列工作:
- 為Apple 開發人員帳戶取得 Apple 推播通知驗證金鑰。
- 在 XCode 中依序前往「App」>「Capabilities」,啟用推播通知。
- 使用 Google 帳戶登入 Firebase。
如果您還沒有 Xcode 專案,只是想試用 Firebase 產品,可以下載我們的快速入門範例。
建立 Firebase 專案
將 Firebase 加入 Apple 應用程式前,請先建立要連結至該應用程式的 Firebase 專案。如要進一步瞭解 Firebase 專案,請參閱「瞭解 Firebase 專案」一文。
建立 Firebase 專案
-
在 Firebase 控制台中,按一下「新增專案」。
-
如要將 Firebase 資源新增至現有 Google Cloud 專案,請輸入專案名稱或從下拉式選單中選取專案。
-
如要建立新專案,請輸入專案名稱。您也可以選擇編輯專案名稱下方顯示的專案 ID。
-
-
如果系統顯示提示,請詳閱並接受 Firebase 條款。
-
按一下「繼續」。
-
(選用) 為專案設定 Google Analytics,以便使用下列 Firebase 產品,獲得最佳體驗: Firebase A/B Testing、 Cloud Messaging、 Crashlytics、 In-App Messaging 和 Remote Config (包括個人化)。
選取現有Google Analytics帳戶或建立新帳戶。如果建立新帳戶,請選取Analytics報表位置,然後接受專案的資料共用設定和Google Analytics條款。
-
按一下「建立專案」 (或「新增 Firebase」,如果要在現有的 Google Cloud 專案中新增 Firebase)。
Firebase 會自動為您的 Firebase 專案佈建資源。完成程序後,系統會將您帶往 Firebase 控制台的 Firebase 專案總覽頁面。
向 Firebase 註冊應用程式
如要在 Apple 應用程式中使用 Firebase,請向 Firebase 專案註冊應用程式。註冊應用程式通常稱為「將應用程式新增至專案」。
前往 Firebase 控制台。
在專案總覽頁面中間,按一下「iOS+」圖示,啟動設定工作流程。
如果已將應用程式新增至 Firebase 專案,請按一下「新增應用程式」,顯示平台選項。
在「軟體包 ID」欄位中輸入應用程式的軟體包 ID。
什麼是軟體包 ID?如何找出軟體包 ID?
軟體包 ID 是 Apple 生態系統中應用程式的專屬 ID。
找出軟體包 ID:在 Xcode 中開啟專案,選取專案導覽器中的頂層應用程式,然後選取「General」(一般) 分頁標籤。
「軟體包 ID」欄位的值是軟體包 ID (例如
com.yourcompany.yourproject
)。請注意,套件 ID 值會區分大小寫,且向 Firebase 專案註冊後,就無法變更這個 Firebase 應用程式的套件 ID。
(選用) 輸入其他應用程式資訊: 「應用程式暱稱」和「App Store ID」。
Firebase 如何使用應用程式暱稱和應用程式商店 ID?
應用程式暱稱:內部使用的便利識別碼,只會顯示在Firebase管理中心
App Store ID:Firebase Dynamic Links 用於將使用者重新導向至 App Store 頁面,Google Analytics 用於將轉換事件匯入 Google Ads。如果應用程式尚未取得 App Store ID,您可以在專案設定中稍後再新增 ID。
按一下 [Register app] (註冊應用程式)。
新增 Firebase 設定檔
按一下「Download GoogleService-Info.plist」,取得應用程式的 Firebase 設定檔 (
GoogleService-Info.plist
)。關於這個設定檔,您需要瞭解哪些事項?
Firebase 設定檔包含專案和應用程式的非祕密專屬 ID。如要進一步瞭解這個設定檔,請參閱「瞭解 Firebase 專案」。
您隨時可以再次下載 Firebase 設定檔。
請確定設定檔名稱未附加額外的字元,例如
(2)
。
將設定檔移至 Xcode 專案的根目錄。如果系統提示,請選取將設定檔新增至所有目標。
如果專案中有多個套件組合 ID,您必須將每個套件組合 ID 與 Firebase 控制台中的已註冊應用程式建立關聯,這樣每個應用程式才能擁有自己的 GoogleService-Info.plist
檔案。
在應用程式中新增 Firebase SDK
使用 Swift Package Manager 安裝及管理 Firebase 依附元件。
- 在 Xcode 中保持開啟應用程式專案,然後依序點選「File」(檔案) 和「Add Packages」(新增 Package)。
- 系統提示時,請新增 Firebase Apple 平台 SDK 存放區:
- 選擇 Firebase Cloud Messaging 程式庫。
- 將
-ObjC
標記新增至目標建構設定的「Other Linker Flags」部分。 - 為獲得最佳 Firebase Cloud Messaging 使用體驗,建議您在 Firebase 專案中啟用 Google Analytics,並在應用程式中加入 Google Analytics 專用 Firebase SDK。您可以選擇不收集 IDFA 的程式庫,也可以選擇收集 IDFA 的程式庫。請參閱常見問題,瞭解 Firebase SDK 中 Google Analytics 的最新模組架構。
- 完成後,Xcode 會自動開始在背景中解析並下載依附元件。
https://github.com/firebase/firebase-ios-sdk.git
上傳 APN 驗證金鑰
將 APNs 驗證金鑰上傳至 Firebase。 如果沒有 APNs 驗證金鑰,請務必在 Apple 開發人員會員中心建立。
-
在 Firebase 控制台的專案中,依序選取齒輪圖示、「專案設定」和「Cloud Messaging」分頁標籤。
-
在「iOS 應用程式設定」下方的「APNs 驗證金鑰」, 按一下「上傳」 按鈕。
-
瀏覽至您儲存金鑰的位置,選取金鑰,然後按一下「開啟」。新增金鑰的 ID (可在 Apple Developer Member Center 中取得),然後按一下「上傳」。
在應用程式中初始化 Firebase
您需要在應用程式中加入 Firebase 初始化程式碼。匯入 Firebase 模組,並設定共用執行個體,如下所示:
- 在
FirebaseCore
中匯入UIApplicationDelegate
模組,以及應用程式委派使用的任何其他 Firebase 模組。舉例來說,如要使用 Cloud Firestore 和 Authentication:import SwiftUI import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
import FirebaseCore import FirebaseFirestore import FirebaseAuth // ...
@import FirebaseCore; @import FirebaseFirestore; @import FirebaseAuth; // ...
- 在應用程式委派的
application(_:didFinishLaunchingWithOptions:)
方法中,設定FirebaseApp
共用例項:// Use Firebase library to configure APIs FirebaseApp.configure()
// Use Firebase library to configure APIs FirebaseApp.configure()
// Use Firebase library to configure APIs [FIRApp configure];
- 如果您使用 SwiftUI,就必須建立應用程式委派,並透過
UIApplicationDelegateAdaptor
或NSApplicationDelegateAdaptor
將其附加至App
結構體。您也必須停用應用程式委派項目的交換。詳情請參閱 SwiftUI 指示。@main struct YourApp: App { // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { NavigationView { ContentView() } } } }
註冊遠端通知
在啟動時或應用程式流程中的所需時間點,註冊應用程式以接收遠端通知。如以下範例所示呼叫registerForRemoteNotifications
:
UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: { _, _ in } ) application.registerForRemoteNotifications()
[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 會自動重試。 如果無法完成訂閱,訂閱項目會擲回錯誤,您可以在完成處理常式中擷取該錯誤,如下所示:
Messaging.messaging().subscribe(toTopic: "weather") { error in print("Subscribed to weather topic") }
[[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:)
:
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 }
- (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); }
建立傳送要求
建立主題後 (方法是在用戶端訂閱主題,或透過伺服器 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
後續步驟
- 您可以使用伺服器訂閱主題的用戶端應用程式執行個體,以及執行其他管理工作。請參閱「在伺服器上管理主題訂閱項目」。