Firebase Cloud Messaging サーバーについて

サーバー側の Firebase Cloud Messaging は、次の 2 つのコンポーネントで構成されます。

  • Google 提供の FCM サーバー
  • アプリサーバーやその他の信頼できる環境Cloud Functions for Firebase など)。

アプリサーバーや信頼できるサーバー環境は、FCM サーバーにメッセージ リクエストを送信し、FCM サーバーからユーザー端末で実行されているクライアント アプリにメッセージが送信されます。

クライアント側の実装の詳細については、使用しているプラットフォーム(iOSAndroidウェブ)のクライアント ガイドをご覧ください。

信頼できるサーバー環境の役割

Firebase Cloud Messaging を使用するクライアント アプリを作成するには、次の条件を満たすサーバー環境をあらかじめ用意する必要があります。

  • クライアントと通信できること。
  • 適切にフォーマットされたメッセージ リクエストを FCM サーバーに送信できること。
  • リクエストを処理し、指数バックオフを使用して再送信できること。
  • サーバーキーとクライアント登録トークンを安全に保存できること。注: サーバーキーをいかなるクライアント コードにも決して含めないでください。
  • XMPP の場合、送信する各メッセージを一意に識別するメッセージ ID をサーバーで生成できること(FCM HTTP 接続サーバーはメッセージ ID を生成し、それらをレスポンスで返します)。XMPP メッセージ ID は送信者 ID ごとに一意のものにする必要があります。

FCM サーバーと対話する方法には Admin SDK を使う方法と未加工プロトコルを使う方法があり、どちらを採用するか決定する必要があります。未加工プロトコル オプションのうち FCM HTTP v1 API が最新のものであり、より安全な認証と柔軟なクロスプラットフォーム メッセージング機能を備えています。以前の HTTPXMPP サーバー プロトコル領域も利用できます。クライアント アプリケーションからのアップストリーム メッセージングを使用するには、XMPP を使用する必要があります。詳しくは FCM サーバー プロトコルをご覧ください。

FCM サーバー プロトコル

現在のところ、FCM は次の未加工サーバー プロトコルを提供しています。

アプリサーバーでは、これらのプロトコルを別々に、または連携して使用できます。複数のプラットフォームにメッセージを送信するうえで最も柔軟性の高い最新のものは FCM HTTP v1 API であり、可能な限りそれを使用するようおすすめします。端末からサーバーへのアップストリーム メッセージングが要件に含まれている場合は、XMPP プロトコルを実装する必要があります。

XMPP メッセージングは、次の点で HTTP メッセージングとは異なります。

  • アップストリームまたはダウンストリーム メッセージ
    • HTTP: ダウンストリームのみ、クラウドから端末。
    • XMPP: アップストリームとダウンストリーム(端末からクラウド、クラウドから端末)。
  • メッセージング(同期または非同期)
    • HTTP: 同期。アプリサーバーは、HTTP POST リクエストとしてメッセージを送信し、レスポンスを待機します。このメカニズムは同期的であり、送信者はレスポンスを受信するまで別のメッセージを送信できません。
    • XMPP: 非同期。アプリサーバーはすべての端末との間で、永続的な XMPP 接続を使用して最大の回線速度でメッセージを送受信します。XMPP 接続サーバーは、受信確認または失敗通知(特別な ACK および NACK JSON エンコード XMPP メッセージの形式)を非同期で送信します。
  • JSON
    • HTTP: HTTP POST として送信された JSON メッセージ。
    • XMPP: XMPP メッセージにカプセル化された JSON メッセージ。
  • 書式なしテキスト
    • HTTP: HTTP POST として送信された書式なしテキスト メッセージ。
    • XMPP: サポートされていません。
  • 複数の登録トークンに送信されるマルチキャスト ダウンストリーム
    • HTTP: JSON メッセージ形式でサポートされます。
    • XMPP: サポートされていません。

HTTP サーバー プロトコルの実装

メッセージを送信するために、アプリサーバーは HTTP ヘッダーと、JSON キー/値ペアで構成される HTTP 本文とを含む POST リクエストを発行します。ヘッダーと本文のオプションの詳細については、アプリサーバーの送信リクエストの作成を参照してください。

XMPP サーバー プロトコルの実装

FCM メッセージの JSON ペイロードは、HTTP プロトコルによく似ていますが、次の点が異なっています。

  • 複数の受信者をサポートしていません。
  • FCM は、ペイロードに必須フィールド message_id を追加します。この ID によって、XMPP 接続でのメッセージが一意に識別されます。FCM からの ACK または NACK は、アプリサーバーから FCM に送られたメッセージを識別するために message_id を使用します。したがって、この message_id が(送信者 ID ごとに)一意で、しかも常に存在していることが重要です。
  • XMPP はサーバーキーを使用することにより、FCM への永続的な接続を認可します。詳細については、送信リクエストを承認するを参照してください。

通常の FCM メッセージに加え、JSON オブジェクトの message_type フィールドで示される制御メッセージが送信されます。値は「ack」、「nack」、「control」のいずれかになります(下の形式を参照)。不明な message_type を含む FCM メッセージはいずれもアプリサーバーで無視できます。

アプリサーバーは、FCM から受信する端末へのメッセージごとに、ACK メッセージを送信する必要があります。NACK メッセージは一切送信する必要がありません。メッセージに対して ACK を送信しないと、そのメッセージは、先に期限切れにならない限り、新しい XMPP 接続が次回確立されたときに FCM から再送信されます。

FCM はさらに、サーバーから端末へのメッセージごとに、ACK または NACK を送信します。どちらも受信しないときは、オペレーション中に TCP 接続が閉じられたことを意味し、サーバーはメッセージを再送信する必要があります。詳細については、フロー制御をご覧ください。

すべてのメッセージ パラメータと、各パラメータをサポートする接続サーバーの一覧については、サーバー リファレンスをご覧ください。

リクエストの形式

ペイロードを含むメッセージ — 通知メッセージ

次に、通知メッセージの XMPP スタンザを示します。

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",  // "to" replaces "registration_ids"
     "notification": {
        "title": "Portugal vs. Denmark”,
        "body”: "5 to 1”
      },
      "time_to_live":"600"
}

  }
  </gcm>
</message>

ペイロードを含むメッセージ - データ メッセージ

次に、アプリサーバーから FCM への JSON メッセージを含む XMPP スタンザを示します。

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",  // "to" replaces "registration_ids"
      "message_id":"m-1366082849205" // new required field
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
      "delivery_receipt_requested": true/false
  }
  </gcm>
</message>

レスポンスの形式

FCM レスポンスが取り得る形式には 3 つあります。最初の形式は通常の「ack」メッセージです。ただし、レスポンスにエラーが含まれる場合、メッセージは下記のように 2 つの異なる形式になります。

ACK メッセージ

次に、FCM からアプリサーバーへの ACK または NACK メッセージを含む XMPP スタンザを示します。

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "from":"REGID",
      "message_id":"m-1366082849205"
      "message_type":"ack"
  }
  </gcm>
</message>

NACK メッセージ

NACK エラーは、message_type ステータス メッセージが「nack」である通常の XMPP メッセージです。NACK メッセージには次の要素が含まれます。

  • NACK エラーコード
  • NACK エラーの説明

次に例を示します。

不正な登録:

<message>
  <gcm xmlns="google:mobile:data">
  {
    "message_type":"nack",
    "message_id":"msgId1",
    "from":"SomeInvalidRegistrationId",
    "error":"BAD_REGISTRATION",
    "error_description":"Invalid token on 'to' field: SomeInvalidRegistrationId"
  }
  </gcm>
</message>

無効な JSON:

<message>
 <gcm xmlns="google:mobile:data">
 {
   "message_type":"nack",
   "message_id":"msgId1",
   "from":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
   "error":"INVALID_JSON",
   "error_description":"InvalidJson: JSON_TYPE_ERROR : Field \"time_to_live\" must be a JSON java.lang.Number: abc"
 }
 </gcm>
</message>

デバイス メッセージ レートの超過:

<message id="...">
  <gcm xmlns="google:mobile:data">
  {
    "message_type":"nack",
    "message_id":"msgId1",
    "from":"REGID",
    "error":"DEVICE_MESSAGE_RATE_EXCEEDED",
    "error_description":"Downstream message rate exceeded for this registration id"
  }
  </gcm>
</message>

すべての NACK エラーコードの一覧については、サーバー リファレンスをご覧ください。特に指示のない限り、NACK が返されたメッセージは再試行しないでください。予期しない NACK エラーコードは INTERNAL_SERVER_ERROR と同じように扱ってください。

スタンザエラー

特定の場合には、スタンザエラーが発生することもあります。スタンザエラーには次の要素が含まれます。

  • スタンザエラー コード
  • スタンザエラーの説明(フリーテキスト)

次に例を示します。

<message id="3" type="error" to="123456789@gcm.googleapis.com/ABC">
  <gcm xmlns="google:mobile:data">
     {"random": "text"}
  </gcm>
  <error code="400" type="modify">
    <bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
    <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
      InvalidJson: JSON_PARSING_ERROR : Missing Required Field: message_id\n
    </text>
  </error>
</message>

制御メッセージ

FCM では、負荷分散を行うために定期的に接続を閉じる必要があります。接続を閉じる前に、FCM は CONNECTION_DRAINING メッセージを送信して、接続がドレインされていてまもなく閉じられることを伝えます。「ドレイン」とは、接続に新たに入ってくるメッセージのフローを遮断し、すでにパイプラインに存在するものはすべてそのまま処理されるようにすることです。CONNECTION_DRAINING メッセージを受信した場合は、必要に応じて新しい接続を開きながら、別の FCM 接続へのメッセージの送信をすぐに開始してください。ただし、元の接続を開いたままにして、その接続で着信する可能性のあるメッセージを受信(および ACK で応答)し続ける必要があります。FCM は、準備が整うと接続閉鎖の開始を処理します。

CONNECTION_DRAINING メッセージは次のようになります。

<message>
  <data:gcm xmlns:data="google:mobile:data">
  {
    "message_type":"control"
    "control_type":"CONNECTION_DRAINING"
  }
  </data:gcm>
</message>

現在サポートされている control_type は、CONNECTION_DRAINING のみです。

配信確認を受信する

Android と Chrome のクライアント アプリの場合、FCM から送信されたメッセージを受信したことを端末が確認したときに、(FCM からアプリサーバーに送信される)配信確認を受け取ることができます。

この機能を有効にするには、アプリサーバーから FCM に送信されるメッセージに delivery_receipt_requested フィールドが含まれている必要があります。このフィールドが true に設定されている場合、特定のメッセージを受信したことを端末が確認したときに、FCM から配信確認が送信されます。

次に、"delivery_receipt_requested"true に設定された JSON メッセージを含む XMPP スタンザを示します。

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",
      "message_id":"m-1366082849205"
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
      "delivery_receipt_requested": true
  }
  </gcm>
</message>

FCM が送信したメッセージを端末が受信したことをアプリサーバーに知らせるために FCM から送信される配信確認の例は、次のとおりです。

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "category":"com.example.yourapp", // to know which app sent it
      "data":
      {
         “message_status":"MESSAGE_SENT_TO_DEVICE",
         “original_message_id”:”m-1366082849205”
         “device_registration_id”: “REGISTRATION_ID”
      },
      "message_id":"dr2:m-1366082849205",
      "message_type":"receipt",
      "from":"gcm.googleapis.com"
  }
  </gcm>
</message>

次の点にご注意ください。

  • "message_type""receipt" に設定されています。
  • "message_status""MESSAGE_SENT_TO_DEVICE" に設定され、端末がメッセージを受信したことを示します。この場合、"message_status" はフィールドではなく、データ ペイロードの一部です。
  • 確認メッセージの ID は元のメッセージ ID で構成されますが、dr2: 接頭辞が付きます。アプリサーバーは、この ID(この例では dr2:m-1366082849205)で ACK を送信する必要があります。
  • 元のメッセージ ID、端末の登録トークン、ステータスは、"data" フィールドの中に含まれます。
  • FCM と端末間の接続が不安定な場合、Firebase Cloud Messaging は複数の重複した配信確認を送信することがあります。このような重複した配信確認は無視してかまいません。

フロー制御

FCM に送信されたすべてのメッセージに対し、ACK または NACK のレスポンスが返されます。どちらのレスポンスも返されていないメッセージは保留中と見なされます。保留中のメッセージ数が 100 に達すると、アプリサーバーは、図 1 に示したように、新しいメッセージの送信を停止し、既存の保留中のメッセージを FCM が確認するまで待機する必要があります。

図 1. メッセージと ACK のフロー

反対に、確認されていないメッセージ数が非常に多い場合、アプリサーバーに負荷をかけすぎないように、FCM はメッセージの送信を停止します。したがって、アプリサーバーは着信メッセージの一定のフローを維持するため、FCM 経由でクライアント アプリケーションから受信したアップストリーム メッセージにできるだけ早く「ACK」で応答する必要があります。上記の保留中のメッセージ数の制限は、これらの ACK には適用されません。保留中のメッセージ数が 100 に達した場合でも、アプリサーバーは、新しいアップストリーム メッセージの配信が妨げられないように、FCM から受信したメッセージに対して ACK を送信し続ける必要があります。

ACK は、1 つの接続のコンテキスト内でのみ有効です。メッセージに対して ACK で応答する前に接続が閉じた場合、アプリサーバーは、FCM がアップストリーム メッセージを再送信するまで待機してから、再度 ACK を送信する必要があります。同様に、接続が閉じられる前に FCM から ACK または NACK を受信しなかった保留中のすべてのメッセージを再度送信する必要があります。

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

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