Mengirim pesan ke beberapa perangkat di platform Apple

Firebase Cloud Messaging menyediakan dua cara untuk menargetkan pesan ke beberapa perangkat:

  • Pesan topik dapat digunakan untuk mengirim pesan ke beberapa perangkat yang mengikuti topik tertentu.
  • Pesan grup perangkat dapat digunakan untuk mengirim satu pesan ke beberapa instance aplikasi yang berjalan di berbagai perangkat dalam sebuah grup.

Tutorial ini berfokus pada pengiriman pesan topik dari server aplikasi Anda menggunakan Admin SDK atau REST API untuk FCM, serta menerima dan menanganinya dalam aplikasi Apple. Halaman ini membahas semua langkah untuk mencapainya, dari penyiapan hingga verifikasi. Jadi, halaman ini juga mencakup langkah-langkah yang mungkin telah Anda selesaikan ketika menyiapkan aplikasi klien Apple untuk FCM atau ketika bersiap Mengirim Pesan Pertama.

Menambahkan Firebase ke project Apple

Bagian ini membahas tugas-tugas yang mungkin telah diselesaikan jika fitur Firebase lainnya telah diaktifkan untuk aplikasi Anda. Khusus untuk FCM, Anda harus mengupload kunci autentikasi APNs dan mendaftar untuk notifikasi jarak jauh.

Prasyarat

  • Instal berikut ini:

    • Xcode 13.3.1 atau yang lebih baru
  • Pastikan project Anda memenuhi persyaratan berikut:

    • Project Anda harus menarget versi platform berikut atau yang lebih baru:
      • iOS 10
      • macOS 10.12
      • tvOS 12
      • watchOS 6
  • Siapkan perangkat Apple fisik untuk menjalankan aplikasi Anda, dan selesaikan tugas-tugas berikut:

    • Dapatkan Kunci Autentikasi Apple Push Notification untuk akun Apple Developer.
    • Di XCode, aktifkan Push Notifications di App > Capabilities.

Jika Anda belum memiliki project Xcode dan hanya ingin mencoba produk Firebase, download salah satu contoh panduan memulai.

Membuat project Firebase

Agar dapat menambahkan Firebase ke aplikasi Apple, Anda perlu membuat project Firebase yang akan dihubungkan ke aplikasi Anda. Buka bagian Memahami Project Firebase untuk mempelajari project Firebase lebih lanjut.

Mendaftarkan aplikasi ke Firebase

Untuk menggunakan Firebase di aplikasi Apple, Anda perlu mendaftarkan aplikasi ke project Firebase. Mendaftarkan aplikasi sering kali disebut sebagai "menambahkan" aplikasi ke project Anda.

  1. Buka Firebase console.

  2. Di bagian tengah halaman ringkasan project, klik ikon iOS+ untuk meluncurkan alur kerja penyiapan.

    Jika Anda sudah menambahkan aplikasi ke project Firebase, klik Add app untuk menampilkan opsi platform.

  3. Masukkan ID paket aplikasi Anda di kolom bundle ID.

  4. (Opsional) Masukkan informasi lain aplikasi: App nickname dan App Store ID.

  5. Klik Register app.

Menambahkan file konfigurasi Firebase

  1. Klik Download GoogleService-Info.plist untuk mendapatkan file konfigurasi platform Apple Firebase Anda (GoogleService-Info.plist).

  2. Pindahkan file konfigurasi ke root project Xcode Anda. Jika diminta, pilih untuk menambahkan file konfigurasi ke semua target.

Jika ada beberapa ID paket dalam project, Anda harus mengaitkan setiap ID paket dengan aplikasi yang terdaftar di Firebase console, sehingga setiap aplikasi dapat memiliki file GoogleService-Info.plist sendiri.

Menambahkan Firebase SDK ke aplikasi

Gunakan Swift Package Manager untuk menginstal dan mengelola dependensi Firebase.

  1. Di Xcode, dengan project aplikasi Anda dalam keadaan terbuka, buka File > Add Packages.
  2. Saat diminta, tambahkan repositori SDK platform Apple Firebase:
  3.   https://github.com/firebase/firebase-ios-sdk
  4. Pilih library Firebase Cloud Messaging.
  5. Untuk mengoptimalkan penggunaan Firebase Cloud Messaging, sebaiknya aktifkan Google Analytics di project Firebase dan tambahkan Firebase SDK untuk Google Analytics ke aplikasi Anda. Anda dapat memilih library tanpa atau dengan pengumpulan IDFA.
  6. Setelah selesai, Xcode akan otomatis mulai me-resolve dan mendownload dependensi Anda di latar belakang.

Mengupload kunci autentikasi APNs

Upload kunci autentikasi APNs Anda ke Firebase. Jika belum memiliki kunci autentikasi APNs, pastikan Anda membuatnya di Apple Developer Member Center.

  1. Pada project Anda di Firebase console, pilih ikon roda gigi, pilih Project Settings, lalu pilih tab Cloud Messaging.

  2. Di bagian APNs authentication key pada iOS app configuration, klik tombol Upload.

  3. Cari lokasi tempat Anda menyimpan kunci, pilih lokasi tersebut, lalu klik Open. Tambahkan ID kunci untuk kunci tersebut (tersedia di Apple Developer Member Center) dan klik Upload.

Melakukan inisialisasi Firebase di aplikasi

Anda harus menambahkan kode inisialisasi Firebase ke aplikasi. Impor modul Firebase dan konfigurasikan instance bersama seperti berikut ini:

  1. Impor modul FirebaseCore dalam UIApplicationDelegate Anda, serta semua modul Firebase lainnya yang digunakan oleh delegasi aplikasi Anda. Misalnya, untuk menggunakan Cloud Firestore dan Authentication:

    Swift

    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          

    Objective-C

    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  2. Konfigurasikan instance bersama FirebaseApp, yang biasanya ada dalam penginisialisasi App atau metode application(_:didFinishLaunchingWithOptions:) delegasi aplikasi:

    Swift

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

    Objective-C

    // Use Firebase library to configure APIs
    [FIRApp configure];

Mendaftar untuk notifikasi jarak jauh

Saat aplikasi dimulai, atau pada waktu lain yang diinginkan dalam alur aplikasi, daftarkan aplikasi Anda untuk mengaktifkan notifikasi jarak jauh. Panggil registerForRemoteNotifications seperti yang ditunjukkan berikut:

Swift

if #available(iOS 10.0, *) {
  // For iOS 10 display notification (sent via APNS)
  UNUserNotificationCenter.current().delegate = self

  let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
  UNUserNotificationCenter.current().requestAuthorization(
    options: authOptions,
    completionHandler: { _, _ in }
  )
} else {
  let settings: UIUserNotificationSettings =
    UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
  application.registerUserNotificationSettings(settings)
}

application.registerForRemoteNotifications()

Objective-C

if ([UNUserNotificationCenter class] != nil) {
  // iOS 10 or later
  // For iOS 10 display notification (sent via APNS)
  [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
      UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
  [[UNUserNotificationCenter currentNotificationCenter]
      requestAuthorizationWithOptions:authOptions
      completionHandler:^(BOOL granted, NSError * _Nullable error) {
        // ...
      }];
} else {
  // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
  UIUserNotificationType allNotificationTypes =
  (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
  UIUserNotificationSettings *settings =
  [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
  [application registerUserNotificationSettings:settings];
}

[application registerForRemoteNotifications];

Membuat aplikasi klien berlangganan topik

Aplikasi klien dapat berlangganan topik yang ada atau membuat topik baru. Jika aplikasi klien berlangganan nama topik baru (nama yang belum ada untuk project Firebase Anda), topik baru dengan nama tersebut akan dibuat di FCM sehingga semua klien dapat berlangganan topik tersebut.

Untuk berlangganan topik, panggil metode langganan dari thread utama aplikasi Anda (FCM tidak aman untuk thread). Jika awalnya permintaan langganan gagal, FCM akan mencoba kembali secara otomatis. Jika tidak berhasil diselesaikan, langganan akan melemparkan error yang dapat Anda terima di pengendali penyelesaian seperti yang ditunjukkan berikut:

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

Panggilan ini mengirimkan permintaan asinkron ke backend FCM dan membuat klien berlangganan topik yang ditentukan. Sebelum memanggil subscribeToTopic:topic, pastikan bahwa instance aplikasi klien telah menerima token pendaftaran melalui callback didReceiveRegistrationToken.

Setiap kali aplikasi dimulai, FCM akan memastikan bahwa klien telah berlangganan semua topik yang diminta. Untuk berhenti berlangganan, panggil unsubscribeFromTopic:topic, dan FCM akan berhenti berlangganan topik di latar belakang.

Menerima dan menangani pesan topik

FCM mengirim pesan topik dengan cara yang sama seperti pesan downstream lainnya.

Terapkan application(_:didReceiveRemoteNotification:fetchCompletionHandler:) seperti yang ditunjukkan berikut:

Swift

func application(_ application: UIApplication,
                 didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult)
                   -> Void) {
  // 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)

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

Mem-build permintaan kirim

Setelah membuat topik, baik dengan membuat instance aplikasi klien berlangganan topik di sisi klien maupun melalui API server, Anda dapat mengirim pesan ke topik tersebut. Jika ini adalah pertama kalinya Anda mem-build permintaan kirim untuk FCM, baca panduan lingkungan server dan FCM untuk mengetahui informasi penting tentang penyiapan dan latar belakang.

Dalam logika pengiriman Anda di backend, tentukan nama topik yang diinginkan seperti yang ditunjukkan di bawah:

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

Perintah 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

Untuk mengirim pesan ke kombinasi topik, tentukan kondisi, yang merupakan ekspresi boolean yang menentukan topik target. Misalnya, kondisi berikut akan mengirim pesan ke perangkat yang berlangganan TopicA dan juga TopicB atau TopicC:

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

FCM mengevaluasi terlebih dahulu setiap kondisi di dalam tanda kurung, lalu mengevaluasi ekspresi dari kiri ke kanan. Pada ekspresi di atas, pengguna yang hanya berlangganan satu topik apa pun tidak akan menerima pesan. Demikian pula, pengguna yang tidak berlangganan TopicA tidak akan menerima pesan. Namun, pengguna dengan kombinasi berikut akan menerimanya:

  • TopicA dan TopicB
  • TopicA dan TopicC

Anda dapat menyertakan hingga lima topik dalam ekspresi kondisional.

Untuk mengirim ke sebuah kondisi:

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",
    }
  }
}

Perintah 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

Langkah berikutnya