iOS で複数のデバイスにメッセージを送信する

Firebase Cloud Messaging では、複数のデバイスをメッセージの対象にする方法が 2 つあります。

このチュートリアルは、FCM 用に HTTP または XMPP プロトコルを使用するアプリサーバーからのトピック メッセージの送信、および iOS アプリでのそれらのメッセージの受信と処理に重点を置いています。このページでは、そのためのセットアップから検証までの全手順を記載しているため、FCM 用の iOS クライアント アプリの設定最初のメッセージ送信をすでに行った場合は、完了済みの手順が含まれている場合があります。

Firebase を iOS プロジェクトに追加する

このセクションで説明しているタスクは、他の Firebase 機能をアプリですでに有効にしている場合は完了している可能性があります。特に FCM の場合は、APNs 認証キーをアップロードしてリモート通知に登録する必要があります。

前提条件

事前に次の環境を準備しておく必要があります。

  • Xcode 9.4.1 以降
  • iOS 8 以降をターゲットにした Xcode プロジェクト
  • Swift プロジェクトには Swift 3.0 以降を使用
  • アプリのバンドル識別子
  • CocoaPods 1.4.0 以降
  • Cloud Messaging の場合:
    • 物理 iOS デバイス
    • Apple Developer アカウントの Apple Push Notification Authentication Key
    • Xcode において [App] > [Capabilities] でプッシュ通知を有効にする

Xcode プロジェクトをまだ用意していない場合に Firebase 機能を試すだけであれば、クイックスタート サンプルをダウンロードしてご利用いただけます。クイックスタートを使用する場合は、バンドル識別子が次のステップで必要になるため、プロジェクト設定からバンドル識別子を忘れずに取得してください。

アプリに Firebase を追加する

Firebase をアプリに追加するには、Firebase プロジェクトと、アプリ用の Firebase 構成ファイルが必要です。

Firebase プロジェクトを作成するには:

  1. Firebase コンソールに移動します。

  2. [プロジェクトを追加] をクリックし、[プロジェクト名] でプロジェクト名を選択するか、新しいプロジェクト名を入力します。

    • アプリに関連付けられた既存の Google プロジェクトがある場合は、[プロジェクト名] プルダウン メニューからプロジェクトを選択します。
    • 既存の Google プロジェクトがない場合は、[プロジェクト名] に新しいプロジェクト名を入力します。
  3. (省略可)プロジェクト ID を編集します。

    Firebase プロジェクトには一意の ID が自動的に割り当てられます。一般公開される Firebase サービスでは、この ID は次のように表示されます。

    • デフォルト Realtime Database URL - your-project-id.firebaseio.com
    • デフォルト Cloud Storage バケット名 - your-project-id.appspot.com
    • デフォルト ホスティング サブドメイン - your-project-id.firebaseapp.com
  4. Firebase コンソールで残りの設定手順を実施した後、[プロジェクトを作成](既存の Google プロジェクトを使用する場合は [Firebase を追加])をクリックします。

Firebase プロジェクトのリソースが自動的にプロビジョニングされます。通常、この処理には数分かかります。処理が完了すると、Firebase コンソールで Firebase プロジェクトの概要ページが表示されます。

これでプロジェクトを用意できました。プロジェクトに iOS アプリを追加できます。

  1. [iOS アプリに Firebase を追加] をクリックして設定手順に沿って操作します。既存の Google プロジェクトをインポートする場合、このステップは自動的に実行されることがあります。その場合は、構成ファイルをダウンロードするだけでかまいません。

  2. メッセージが表示されたら、アプリのバンドル ID を入力します。必ずアプリで使用しているバンドル ID を入力してください。バンドル ID を設定できるのは、アプリを Firebase プロジェクトに追加するときだけです。

  3. Firebase iOS 構成ファイルをアプリに追加します。

    1. [GoogleService-Info.plist をダウンロード] をクリックして、Firebase iOS 構成ファイル(GoogleService-Info.plist)を入手します。

      Firebase iOS 構成ファイルはいつでも再ダウンロードできます。

    2. 構成ファイルを Xcode プロジェクトのルートに移動します。メッセージが表示されたら、構成ファイルをすべてのターゲットに追加するオプションを選択します。

  4. 初期化コードを追加したらアプリを実行して、Firebase を正常にインストールしたという確認を Firebase コンソールに送信します。

SDK を追加する

新しいプロジェクトを設定する場合は、SDK をインストールする必要があります。この操作は、Firebase プロジェクトの作成の一環として完了済みの場合があります。

ライブラリをインストールするときは CocoaPods を使用することをおすすめします。インストール手順に沿って CocoaPods をインストールしてください。CocoaPods を使用しない場合は、CocoaPods を使用せずに SDK フレームワークを直接統合する方法もあります。

クイックスタート サンプルをダウンロードしていずれかのプログラムを実行する場合、Xcode プロジェクトと Podfile がすでに存在していても、ポッドをインストールして GoogleService-Info.plist ファイルをダウンロードする必要があります。Firebase ライブラリをプロジェクトに統合する場合は、使用するライブラリ用のポッドを追加する必要があります。

  1. Xcode プロジェクトをまだ用意していない場合は作成します。

  2. Podfile がない場合は作成します。

    $ cd your-project directory
    $ pod init
    
  3. インストールするポッドを追加します。次のようにして Podfile にポッドを含めます。

    pod 'Firebase/Core'
    pod 'Firebase/Messaging'
    

    これにより、iOS アプリで Firebase を稼働させるために必要なライブラリが、Firebase 向け Google アナリティクスとともに追加されます。現在使用可能なポッドとサブスペックのリストを以下に示します。機能固有の設定ガイドへのリンクもあります。

  4. ポッドをインストールし、.xcworkspace ファイルを開いて Xcode でプロジェクトを確認します。

    $ pod install
    $ open your-project.xcworkspace
    
  5. Firebase コンソールで GoogleService-Info.plist ファイルをダウンロードし、アプリに含めます。

APNs 認証キーをアップロードする

APNs 認証キーを Firebase にアップロードします。APNs 認証キーがない場合は、FCM での APNs の構成に関する説明をご覧ください。

  1. Firebase コンソールのプロジェクト内で歯車アイコンを選択し、[プロジェクトの設定]、[クラウド メッセージング] タブの順に選択します。

  2. [iOS アプリの設定] の下の [APNs 認証キー] で [アップロード] ボタンをクリックします。

  3. キーが保存されている場所に移動し、キーを選択して [開く] をクリックします。キーのキー ID(Apple Developer Member Center の [Certificates, Identifiers & Profiles] で確認できます)を追加し、[アップロード] をクリックします。

アプリで Firebase を初期化する

Firebase 初期化コードをアプリケーションに追加する必要があります。Firebase モジュールをインポートして、次に示すように共有インスタンスを構成します。

  1. UIApplicationDelegate で Firebase モジュールをインポートします。

    Swift

    import Firebase
    

    Objective-C

    @import Firebase;
    
  2. FirebaseApp 共有インスタンスを構成します。通常はアプリケーションの application:didFinishLaunchingWithOptions: メソッドで行います。

    Swift

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

    Objective-C

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

リモート通知に登録する

起動時またはアプリケーション フローの必要な時点で、リモート通知にアプリを登録します。次のように registerForRemoteNotifications を呼び出します。

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

クライアント アプリをトピックに登録する

クライアント アプリを既存のトピックに登録することも、新しいトピックを作成することもできます。クライアント アプリを新しいトピック名(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 は、他のダウンストリーム メッセージと同じようにトピック メッセージを配信します。

AppDelegate application:didReceiveRemoteNotification: を次のように実装します。

Swift

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
  // 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)
}

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 {
  // 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 message ID.
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

  // Print full message.
  NSLog(@"%@", userInfo);
}

- (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 message ID.
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

  // Print full message.
  NSLog(@"%@", userInfo);

  completionHandler(UIBackgroundFetchResultNewData);
}

ビルド送信リクエスト

Firebase Cloud Messaging トピックへのメッセージを送信する方法は、個々のデバイスやユーザー グループ宛てのメッセージを送信する場合とよく似ています。アプリサーバーは to キーに /topics/yourTopic などの値を設定します。デベロッパーは、正規表現 "/topics/[a-zA-Z0-9-_.~%]+" に一致するすべてのトピック名を選択できます。

複数のトピックの組み合わせに送信する場合、アプリサーバーは(to キーではなく)condition キーで、対象のトピックを指定するブール条件を設定する必要があります。たとえば、TopicA と、TopicB または TopicC のいずれかに登録されたデバイスにメッセージを送信する場合には、次のようになります。

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

FCM はまず、かっこ内の条件を評価し、次に左から右に式を評価していきます。上記の式では、いずれか 1 つのトピックだけに登録したユーザーはメッセージを受信しません。同様に、TopicA に登録していないユーザーはメッセージを受信しません。メッセージを受信するのは、次の組み合わせの場合のみです。

  • TopicA と TopicB
  • TopicA と TopicC

条件式には最大 5 つのトピックを含めることができ、かっこを使用できます。使用できる演算子は &&||! です。! の使用方法に注意してください。

!('TopicA' in topics)

この式では、どのトピックにも登録されていないアプリ インスタンスを含め、TopicA に登録されていないアプリ インスタンスすべてがメッセージを受信します。

アプリサーバーのキーの詳細については、選択した接続サーバー プロトコル(HTTP または XMPP)のリファレンス情報をご覧ください。このページでは、メッセージをトピックに送信する方法として HTTP と XMPP の両方の例を示しています。

トピック HTTP POST リクエスト

単一のトピックに送信します。

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{
  "to" : /topics/foo-bar",
  "priority" : "high",
  "notification" : {
    "body" : "This is a Firebase Cloud Messaging Topic Message!",
    "title" : "FCM Message",
  }
}

「犬」('dogs')または「猫」('cats')のトピックに登録されたデバイスに送信します。

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{
  "condition": "'dogs' in topics || 'cats' in topics",
  "priority" : "high",
  "notification" : {
    "body" : "This is a Firebase Cloud Messaging Topic Message!",
    "title" : "FCM Message",
  }
}

トピック HTTP レスポンス

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

トピック XMPP メッセージ

単一のトピックに送信します。

<message id="">
  <gcm xmlns="google:mobile:data">

{
  "to" : /topics/foo-bar",
  "priority" : "high",
  "notification" : {
    "body" : "This is a Firebase Cloud Messaging Topic Message!",
    "title" : "FCM Message",
  }
}
  </gcm>
</message>

「犬」('dogs')または「猫」('cats')のトピックに登録されたデバイスに送信します。

<message id="">
  <gcm xmlns="google:mobile:data">

{
  "condition": "'dogs' in topics || 'cats' in topics",
  "priority" : "high",
  "notification" : {
    "body" : "This is a Firebase Cloud Messaging Topic Message!",
    "title" : "FCM Message",
  }
}
  </gcm>
</message>

トピック XMPP レスポンス

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

FCM サーバーがトピック送信リクエストに成功または失敗のレスポンスを返すまでに、最大 30 秒の遅延が発生する可能性があります。それに応じて、リクエスト内でアプリサーバーのタイムアウト値を必ず設定してください。

メッセージ オプションの全一覧については、選択した接続サーバー プロトコル(HTTP または XMPP)のリファレンス情報をご覧ください。

次のステップ

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。