向 Apple 平台上的多個裝置發送訊息

若要將訊息定位到多個設備,請使用主題訊息傳遞。此功能可讓您向選擇加入特定主題的多個裝置發送訊息。

本教學重點在於使用適用於 FCM 的Admin SDKREST API從應用程式伺服器發送主題訊息,以及在 Apple 應用程式中接收和處理它們。此頁面列出了實現此目的的所有步驟(從設定到驗證),因此,如果您已為 FCM設定了 Apple 用戶端應用程式或完成了發送第一則訊息的步驟,則它可能涵蓋您已完成的步驟。

將 Firebase 新增到您的 Apple 項目

如果您已經為您的應用程式啟用了其他 Firebase 功能,本部分將介紹您可能已完成的任務。特別是對於 FCM,您需要上傳 APNs 身份驗證金鑰註冊遠端通知

先決條件

  • 安裝以下內容:

    • Xcode 14.1 或更高版本
  • 確保您的專案符合以下要求:

    • 您的專案必須針對這些平台版本或更高版本:
      • iOS 11
      • macOS 10.13
      • 電視作業系統12
      • watchOS 6
  • 設定實體 Apple 裝置來運行您的應用程序,並完成以下任務:

    • 為您的Apple 開發者帳戶取得 Apple 推播通知驗證金鑰。
    • App > Capability下的 XCode 中啟用推播通知。

如果您還沒有 Xcode 專案而只想嘗試 Firebase 產品,則可以下載我們的快速入門範例之一。

創建 Firebase 項目

在將 Firebase 新增至您的 Apple 應用程式之前,您需要建立一個 Firebase 專案來連接到您的應用程式。請造訪了解 Firebase 專案以了解有關 Firebase 專案的更多資訊。

向 Firebase 註冊您的應用

要在 Apple 應用程式中使用 Firebase,您需要向 Firebase 專案註冊您的應用程式。註冊您的應用程式通常稱為將您的應用程式「新增」到您的專案中。

  1. 轉到Firebase 控制台

  2. 在專案概述頁面的中心,按一下iOS+圖示以啟動設定工作流程。

    如果您已將應用程式新增至 Firebase 項目,請按一下新增應用程式以顯示平台選項。

  3. 捆綁包 ID欄位中輸入應用程式的捆綁包 ID。

  4. (可選)輸入其他應用程式資訊:應用程式暱稱應用程式商店 ID

  5. 點擊註冊應用程式

新增 Firebase 設定檔

  1. 按一下「下載 GoogleService-Info.plist」以取得 Firebase Apple 平台設定檔 ( GoogleService-Info.plist )。

  2. 將設定檔移至 Xcode 專案的根目錄中。如果出現提示,請選擇將設定檔新增至所有目標。

如果您的專案中有多個捆綁包 ID,則必須將每個捆綁包 ID 與 Firebase 控制台中註冊的應用程式關聯,以便每個應用程式都可以擁有自己的GoogleService-Info.plist檔案。

將 Firebase SDK 新增到您的應用

使用 Swift Package Manager 安裝和管理 Firebase 相依性。

  1. 在 Xcode 中,開啟應用程式項目,導覽至File > Add Packages
  2. 出現提示時,新增 Firebase Apple 平台 SDK 儲存庫:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. 選擇 Firebase 雲端訊息傳遞庫。
  5. -ObjC標誌新增至目標建置設定的「其他連結器標誌」部分。
  6. 為了獲得 Firebase Cloud Messaging 的最佳體驗,我們建議在您的 Firebase 專案中啟用 Google Analytics ,並將適用於 Google Analytics 的 Firebase SDK 新增至您的應用程式。您可以選擇沒有 IDFA 收集或有 IDFA 收集的庫。
  7. 完成後,Xcode 將自動開始在背景解析並下載您的依賴項。

上傳您的 APNs 驗證金鑰

將您的 APNs 驗證金鑰上傳到 Firebase。如果您還沒有 APNs 驗證金鑰,請確保在Apple 開發者會員中心建立一個。

  1. 在 Firebase 控制台的項目內,選擇齒輪圖標,選擇項目設置,然後選擇雲端訊息傳遞選項卡。

  2. iOS 應用程式設定下的APNs 驗證金鑰中,按一下上傳按鈕。

  3. 瀏覽到儲存金鑰的位置,選擇它,然後按一下「開啟」 。新增金鑰的金鑰 ID(可在Apple 開發者會員中心取得)並點選Upload

在您的應用程式中初始化 Firebase

您需要將 Firebase 初始化程式碼新增到您的應用程式中。導入 Firebase 模組並配置共享實例,如下所示:

  1. UIApplicationDelegate中導入FirebaseCore模組,以及應用程式委託使用的任何其他Firebase 模組。例如,要使用 Cloud Firestore 和身份驗證:

    斯威夫特使用者介面

    import SwiftUI
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    迅速

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    Objective-C

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  2. 在應用程式委託的application(_:didFinishLaunchingWithOptions:)方法中設定FirebaseApp共享實例:

    斯威夫特使用者介面

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    迅速

    // Use Firebase library to configure APIs
    FirebaseApp.configure()

    Objective-C

    // Use Firebase library to configure APIs
    [FIRApp configure];
  3. 如果您使用 SwiftUI,則必須建立應用程式委託並透過UIApplicationDelegateAdaptorNSApplicationDelegateAdaptor將其附加到您的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()

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 會自動重試。對於無法完成訂閱的情況,訂閱會引發錯誤,您可以在完成處理程序中捕獲該錯誤,如下所示:

迅速

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:)如下所示:

迅速

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);
}

建構發送請求

建立主題後,您可以透過在客戶端訂閱該主題的客戶端應用程式實例或透過伺服器 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);
  });

爪哇

// 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)

// 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);

休息

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 -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以及TopicBTopicC的裝置發送訊息:

"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"

FCM 首先計算括號中的任何條件,然後從左到右計算表達式。在上面的表達式中,訂閱任何單一主題的用戶都不會收到訊息。同樣,未訂閱TopicA用戶也不會收到該訊息。這些組合確實收到了它:

  • TopicATopicB
  • TopicATopicC

您最多可以在條件表達式中包含五個主題。

發送到條件:

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);
  });

爪哇

// 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)

// 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);

休息

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 -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

下一步