ส่งข้อความไปยังอุปกรณ์หลายเครื่องบนแพลตฟอร์ม Apple

ในการกำหนดเป้าหมายข้อความไปยังอุปกรณ์หลายเครื่อง ให้ใช้ ข้อความตามหัวข้อ ช่วงเวลานี้ ที่ช่วยให้คุณดำเนินการ ส่งข้อความไปยังอุปกรณ์หลายเครื่องที่เลือกเข้าร่วมหัวข้อเฉพาะได้

บทแนะนำนี้มุ่งเน้นไปที่การส่งข้อความตามหัวข้อจากเซิร์ฟเวอร์แอปของคุณโดยใช้ Admin SDK หรือ API ของ REST FCM แล้วรับและจัดการคำสั่งซื้อ ในแอป Apple หน้านี้จะแสดงขั้นตอนทั้งหมดในการบรรลุเป้าหมายนี้ ตั้งแต่การตั้งค่าไปจนถึง ซึ่งอาจครอบคลุมถึงขั้นตอนที่คุณได้ดำเนินการไปแล้วหากคุณมี ตั้งค่าแอปไคลเอ็นต์ของ Apple สำหรับ FCM หรือทำตามขั้นตอนในการส่งข้อความแรกของคุณ

เพิ่ม Firebase ลงในโปรเจ็กต์ Apple

ส่วนนี้ครอบคลุมงานที่คุณอาจทำเสร็จแล้วหากเปิดใช้แล้ว ฟีเจอร์อื่นๆ ของ Firebase สำหรับแอป สำหรับ FCM คุณสามารถ จำเป็นต้อง อัปโหลดคีย์การตรวจสอบสิทธิ์ APNs และ ลงทะเบียนรับการแจ้งเตือนระยะไกล

ข้อกำหนดเบื้องต้น

  • ติดตั้งสิ่งต่อไปนี้

    • Xcode 15.2 ขึ้นไป
  • ตรวจสอบว่าโปรเจ็กต์เป็นไปตามข้อกำหนดต่อไปนี้

    • โปรเจ็กต์ของคุณต้องกำหนดเป้าหมายเวอร์ชันแพลตฟอร์มต่อไปนี้หรือเวอร์ชันที่ใหม่กว่า
      • iOS 13
      • macOS 10.15
      • TVOS 13
      • WatchOS 7
  • ตั้งค่าอุปกรณ์ Apple จริงเพื่อเรียกใช้แอป แล้วทำงานต่อไปนี้ให้เสร็จ

    • รับคีย์การตรวจสอบสิทธิ์ข้อความ Push ของ Apple สำหรับ บัญชีนักพัฒนาแอป Apple
    • เปิดใช้ข้อความ Push ใน XCode ในส่วน App > ความสามารถ

หากยังไม่มีโปรเจ็กต์ Xcode และต้องการลองใช้ Firebase คุณสามารถดาวน์โหลดตัวอย่างการเริ่มต้นอย่างรวดเร็วของเราได้

สร้างโปรเจ็กต์ Firebase

คุณต้องสร้าง Firebase ก่อนจึงจะเพิ่ม Firebase ลงในแอป Apple ได้ เพื่อเชื่อมต่อกับแอปของคุณ ไปที่เว็บไซต์ ทำความเข้าใจโปรเจ็กต์ Firebase เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ โปรเจ็กต์ Firebase

ลงทะเบียนแอปด้วย Firebase

หากต้องการใช้ Firebase ในแอป Apple คุณต้องลงทะเบียนแอปด้วย โปรเจ็กต์ Firebase การลงทะเบียนแอปมักเรียกว่า "การเพิ่ม" แอปของคุณไปยัง

  1. ไปที่คอนโซลของ Firebase

  2. ที่ตรงกลางของหน้าภาพรวมโปรเจ็กต์ ให้คลิกไอคอน iOS+ เพื่อเปิดเวิร์กโฟลว์การตั้งค่า

    หากคุณเพิ่มแอปลงในโปรเจ็กต์ Firebase แล้ว ให้คลิกเพิ่มแอป เพื่อแสดงตัวเลือกแพลตฟอร์ม

  3. ป้อนรหัสชุดของแอปในช่องรหัสแพ็กเกจ

  4. (ไม่บังคับ) ป้อนข้อมูลอื่นๆ ของแอป ชื่อเล่นแอปและรหัส App Store

  5. คลิกลงทะเบียนแอป

เพิ่มไฟล์การกำหนดค่า Firebase

  1. คลิก Download GoogleService-Info.plist เพื่อรับ Firebase Apple ไฟล์การกำหนดค่าแพลตฟอร์ม (GoogleService-Info.plist)

  2. ย้ายไฟล์การกำหนดค่าไปยังรูทของโปรเจ็กต์ Xcode หากได้รับข้อความแจ้ง เลือกเพื่อเพิ่มไฟล์การกำหนดค่าไปยังเป้าหมายทั้งหมด

หากมีรหัสชุดหลายรายการในโปรเจ็กต์ คุณต้องเชื่อมโยงแพ็กเกจแต่ละรายการ ด้วยแอปที่ลงทะเบียนแล้วในคอนโซล Firebase เพื่อให้แต่ละแอปมี ไฟล์ GoogleService-Info.plist ของตัวเอง

เพิ่ม Firebase SDK ลงในแอป

ใช้ Swift Package Manager เพื่อติดตั้งและจัดการทรัพยากร Dependency ของ Firebase

  1. เปิดโปรเจ็กต์แอปใน Xcode แล้วไปที่ไฟล์ > เพิ่มแพ็กเกจ
  2. เมื่อได้รับข้อความแจ้ง ให้เพิ่มที่เก็บ SDK สำหรับแพลตฟอร์ม Firebase ของ Apple ดังนี้
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. เลือกไลบรารี Firebase Cloud Messaging
  5. เพิ่มแฟล็ก -ObjC ลงในส่วนแฟล็ก Linker อื่นๆ ของการตั้งค่าบิลด์ของเป้าหมาย
  6. เราขอแนะนำเพื่อประสบการณ์การใช้งาน Firebase Cloud Messaging ที่ดีที่สุด กำลังเปิดใช้ Google Analytics ในโปรเจ็กต์ Firebase และเพิ่ม Firebase SDK สำหรับ Google Analytics ลงในแอป คุณสามารถ ให้เลือกไลบรารีที่ไม่มีการรวบรวม IDFA หรือมีคอลเล็กชัน IDFA
  7. เมื่อเสร็จแล้ว Xcode จะเริ่มแก้ปัญหาและดาวน์โหลด ทรัพยากร Dependency ในเบื้องหลัง

อัปโหลดคีย์การตรวจสอบสิทธิ์ APNs

อัปโหลดคีย์การตรวจสอบสิทธิ์ APN ไปยัง Firebase หากคุณยังไม่มีคีย์การตรวจสอบสิทธิ์ APNs โปรดสร้างคีย์ใน Apple Developer Member Center

  1. ภายในโปรเจ็กต์ในคอนโซล Firebase ให้เลือก ไอคอนรูปเฟือง, เลือก การตั้งค่าโปรเจ็กต์ แล้วเลือก แท็บการรับส่งข้อความในระบบคลาวด์

  2. ในคีย์การตรวจสอบสิทธิ์ AAP ในส่วนการกำหนดค่าแอป iOS ให้คลิกอัปโหลด

  3. เรียกดูตำแหน่งที่คุณบันทึกกุญแจไว้ จากนั้นเลือกคีย์แล้วคลิก เปิด เพิ่มรหัสคีย์สำหรับคีย์ (มีอยู่ใน Apple Developer Member Center) แล้วคลิก อัปโหลด

เริ่มต้น Firebase ในแอป

คุณจะต้องเพิ่มโค้ดการเริ่มต้น Firebase ลงในแอปพลิเคชัน นำเข้า โมดูล Firebase และกำหนดค่าอินสแตนซ์ที่แชร์ตามที่แสดงด้านล่าง

  1. นำเข้าโมดูล 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;
    // ...
          
  2. กําหนดค่า 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];
  3. หากใช้ SwiftUI คุณต้องสร้างการมอบสิทธิ์แอปพลิเคชันและแนบการมอบสิทธิ์ ไปยังโครงสร้าง App ของคุณผ่าน UIApplicationDelegateAdaptor หรือ NSApplicationDelegateAdaptor คุณต้องปิดใช้ SWizzing ที่มอบสิทธิ์ของแอปด้วย สำหรับ สำหรับข้อมูลเพิ่มเติม โปรดดูวิธีการของ 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);
}

สร้างคำขอส่งคำขอ

หลังจากสร้างหัวข้อแล้ว ไม่ว่าจะด้วยการสมัครใช้บริการอินสแตนซ์แอปไคลเอ็นต์ หัวข้อในฝั่งไคลเอ็นต์หรือผ่าน 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

หากต้องการส่งข้อความไปยังกลุ่มหัวข้อ ระบุ condition ซึ่งเป็นนิพจน์บูลีนที่ระบุพารามิเตอร์ หัวข้อเป้าหมาย ตัวอย่างเช่น เงื่อนไขต่อไปนี้จะส่งข้อความถึง อุปกรณ์ที่สมัครใช้บริการ TopicA และ TopicB หรือ TopicC:

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

FCM จะประเมินเงื่อนไขในวงเล็บก่อน จากนั้นจึงประเมิน นิพจน์จากซ้ายไปขวา ในนิพจน์ข้างต้น ผู้ใช้สมัครรับข้อมูล หัวข้อใดหัวข้อหนึ่งไม่ได้รับข้อความ ในทำนองเดียวกัน ผู้ใช้ที่ไม่ การติดตาม TopicA ไม่ได้รับข้อความ การผสมผสานเหล่านี้ รับเลย

  • TopicA และ TopicB
  • TopicA และ TopicC

คุณสามารถรวมหัวข้อไว้ในนิพจน์แบบมีเงื่อนไขได้สูงสุด 5 หัวข้อ

วิธีส่งไปยังเงื่อนไข

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

ขั้นตอนถัดไป