如要將訊息指定給多部裝置,請使用主題訊息傳送功能。這項功能可讓你向已選擇加入特定主題的多部裝置傳送訊息。
本教學課程著重於使用 Admin SDK 或 FCM 的 REST API,從應用程式伺服器傳送主題訊息,以及在 Apple 應用程式中接收及處理這些訊息。本頁面列出從設定到驗證的所有步驟,因此如果您已為 FCM 設定 Apple 用戶端應用程式,或已完成傳送第一則訊息的步驟,這裡可能會涵蓋您已完成的步驟。
將 Firebase 新增至 Apple 專案
本節將說明如果您已為應用程式啟用其他 Firebase 功能,可能已完成的作業。具體來說,您需要上傳 APNs 驗證金鑰,並註冊遠端通知。FCM
事前準備
安裝下列項目:
- Xcode 15.2 以上版本
請確認您的專案符合下列規定:
- 您的專案必須指定以下平台版本或以上版本:
- iOS 13
- macOS 10.15
- tvOS 13
- watchOS 7
- 您的專案必須指定以下平台版本或以上版本:
設定實體 Apple 裝置來執行應用程式,並完成下列工作:
- 取得 Apple Developer 帳戶的 Apple 推播通知驗證金鑰。
- 在 XCode 中依序前往「App」>「Capabilities」,啟用推播通知。
- 使用 Google 帳戶登入 Firebase。
如果您尚未建立 Xcode 專案,但想試用 Firebase 產品,可以下載我們的快速入門範例。
建立 Firebase 專案
如要將 Firebase 新增至 Apple 應用程式,您必須先建立 Firebase 專案,然後再連結至應用程式。請參閱「瞭解 Firebase 專案」,進一步瞭解 Firebase 專案。
建立 Firebase 專案
-
在 Firebase 控制台中,按一下「新增專案」。
-
如要將 Firebase 資源新增至現有 Google Cloud 專案,請輸入專案名稱,或從下拉式選單中選取。
-
如要建立新專案,請輸入所需的專案名稱。您也可以視需要編輯專案名稱下方顯示的專案 ID。
-
-
系統提示時,請詳閱並接受 Firebase 條款。
-
按一下「繼續」。
-
(選用) 為專案設定 Google Analytics,即可在使用下列任何 Firebase 產品時,獲得最佳體驗:
選取現有的 Google Analytics 帳戶,或建立新帳戶。
如果您建立新帳戶,請選取Analytics報表位置,然後接受專案的資料共用設定和 Google Analytics 條款。
-
按一下「建立專案」 (如果您使用的是現有的 Google Cloud 專案,請按一下「新增 Firebase」)。
Firebase 會自動為 Firebase 專案佈建資源。程序完成後,您會前往 Firebase 主控台的 Firebase 專案總覽頁面。
透過 Firebase 註冊應用程式
如要在 Apple 應用程式中使用 Firebase,您必須將應用程式註冊至 Firebase 專案。註冊應用程式通常稱為將應用程式「新增」至專案。
前往 Firebase 控制台。
在專案總覽頁面的中間,按一下 iOS+ 圖示,啟動設定工作流程。
如果您已將應用程式新增至 Firebase 專案,請按一下「Add app」,顯示平台選項。
在「軟體包 ID」欄位中輸入應用程式的軟體包 ID。
什麼是軟體包 ID?如何找出軟體包 ID?
軟體包 ID 可用來識別 Apple 生態系統中的應用程式。
找出軟體包 ID:在 Xcode 中開啟專案,選取專案導覽器中的頂層應用程式,然後選取「General」分頁。
「Bundle Identifier」欄位的值為軟體包 ID (例如
com.yourcompany.yourproject
)。請注意,套件 ID 值會區分大小寫,且在 Firebase 專案註冊此 Firebase 應用程式後,就無法變更。
(選用) 輸入其他應用程式資訊:應用程式暱稱和 App Store ID。
應用程式暱稱和 應用程式商店 ID在 Firebase 中如何使用?
應用程式暱稱:內部方便取用識別碼,僅會顯示在 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 Apple 平台設定檔 (
GoogleService-Info.plist
)。您需要瞭解這個設定檔的哪些資訊?
Firebase 設定檔包含專案的非祕密專屬 ID。如要進一步瞭解這個設定檔,請參閱「瞭解 Firebase 專案」。
您隨時可以重新下載 Firebase 設定檔。
請確認設定檔名稱未附加額外的字元,例如
(2)
。
將設定檔移至 Xcode 專案的根目錄。如果系統顯示提示,請選取將設定檔新增至所有目標。
如果專案中有多個套件 ID,您必須在 Firebase 主控台中將每個套件 ID 與已註冊的應用程式建立關聯,讓每個應用程式都有自己的 GoogleService-Info.plist
檔案。
在應用程式中新增 Firebase SDK
使用 Swift Package Manager 安裝及管理 Firebase 依附元件。
- 在 Xcode 中保持開啟應用程式專案,然後依序點選「File」>「Add Packages」。
- 系統提示時,請新增 Firebase Apple 平台 SDK 存放區:
- 選擇 Firebase Cloud Messaging 程式庫。
- 將
-ObjC
標記新增至目標的建構設定「Other Linker Flags」部分。 - 為提供最佳的 Firebase Cloud Messaging 體驗,建議您在 Firebase 專案中啟用 Google Analytics,並將 Google Analytics 專用 Firebase SDK 新增至應用程式。您可以選擇不收集 IDFA 的程式庫,也可以選擇收集 IDFA 的程式庫。
- 完成後,Xcode 就會自動開始在背景中解析並下載依附元件。
https://github.com/firebase/firebase-ios-sdk.git
上傳 APNs 驗證金鑰
將 APNs 驗證金鑰上傳至 Firebase。如果您尚未取得 APN 驗證金鑰,請務必前往 Apple Developer Member Center 建立金鑰。
-
在 Firebase 控制台的專案中,依序選取齒輪圖示、「Project Settings」(專案設定),然後選取「Cloud Messaging」分頁。
-
在「iOS 應用程式設定」下方的「APNs 驗證金鑰」中,按一下「上傳」按鈕。
-
瀏覽至儲存金鑰的位置,選取金鑰,然後按一下「Open」。新增金鑰的金鑰 ID (可在 Apple Developer Member Center 中找到),然後按一下「上傳」。
在應用程式中初始化 Firebase
您必須在應用程式中加入 Firebase 初始化程式碼。匯入 Firebase 模組,並設定共用例項,如下所示:
- 在
UIApplicationDelegate
中匯入FirebaseCore
模組,以及應用程式委派程式使用的任何其他 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
結構體。您也必須停用應用程式委派程式 swizzling。詳情請參閱 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
後續步驟
- 您可以使用伺服器讓用戶端應用程式例項訂閱主題,並執行其他管理工作。請參閱「管理伺服器上的主題訂閱項目」。