Chrome 上の Firebase Cloud Messaging クライアントの実装

Firebase Cloud Messaging では、次の 2 つの方法で Chrome のメッセージング サービスを提供します。

  • Chrome のウェブサイトでは、Webpush 標準に従い、service worker とウェブアプリ マニフェストを利用してプッシュ メッセージングを実装できます。
  • Chrome アプリと拡張機能により、chrome.gcm API を介して直接 FCM サービスにアクセスできます。

このページの残りの部分では、Chrome アプリと拡張機能に関する FCM のサポートについてのみ説明します。ウェブサイトのサポートについては、プッシュ メッセージングに関する Codelab をご覧ください。

Chrome アプリと拡張機能については、FCM を使用することで、Chrome インスタンスがサーバーからメッセージ データを送受信できるようになります。chrome.gcm API を利用すると、Chrome アプリや拡張機能から FCM サービスにアクセスできます。サービスはアプリや拡張機能が現在実行されていない場合でも動作します。たとえば、ユーザーのカレンダー アプリが開かれていないときでも、カレンダー アプリの更新をユーザーにプッシュすることができます。

API とサービスの両方を使用するには、Google API の利用規約Google Cloud Platform の利用規約に同意する必要があります。

Firebase Cloud Messaging を完全に実装するには、クライアント側とサーバー側の両方で実装が必要になります。サーバー側の実装の詳細については、Firebase Cloud Messaging サーバーについてをご覧ください。

Firebase プロジェクトと FCM 送信者 ID を作成する

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

  1. Firebase console で [新規プロジェクトを作成] を選択します。
  2. プロジェクト名を指定し、[プロジェクトを作成] をクリックします。
  3. 左上にあるプロジェクト名の隣の歯車アイコン、[プロジェクトの設定] の順に選択します。
  4. [クラウド メッセージング] タブを選択します。このページで自分の送信者 ID を特定できます。この値は後で FCM 送信者 ID として使用するのでコピーしておきます。

Chrome アプリまたは拡張機能を設定する

マニフェストに権限を追加する

gcm サービスを使用するには、gcm 権限を manifest.json に宣言する必要があります。


"permissions": [
  "gcm", ... // Other permissions, like "storage"
]

下のサンプルコードを実行する場合は、chrome.storage API を使用してデータを永続化するために storage 権限も必要になります。

Chrome アプリまたは拡張機能を記述する

FCM 登録トークンを取得する

Chrome アプリまたは拡張機能は、メッセージを受け取れるように FCM 接続サーバーに登録しておく必要があります。これを行うには、chrome.gcm.register を呼び出して、送信者 ID のリストを渡します(すべて Firebase console から行えます)。アプリや拡張機能では、コールバック関数を渡してエラーが chrome.runtime.lastError プロパティにセットされているかどうかをチェックすることで、登録が成功したかどうかを確認する必要があります。登録が成功したら、アプリや拡張機能で受信する登録トークンを HTTPS などの安全な方法でアプリサーバーに送り返します。登録に失敗した場合は、chrome.runtime.lastError で特定されるエラーをアプリや拡張機能で処理し、後で再試行するようにします。

アプリや拡張機能で別の送信者からのメッセージを受け取りたい場合は、新しい送信者リストを指定して chrome.gcm.register を再度呼び出すと新しい登録トークンが返されます。


function registerCallback(registrationId) {
  if (chrome.runtime.lastError) {
    // When the registration fails, handle the error and retry the
    // registration later.
    return;
  }

  // Send the registration token to your application server.
  sendRegistrationId(function(succeed) {
    // Once the registration token is received by your server,
    // set the flag such that register will not be invoked
    // next time when the app starts up.
    if (succeed)
      chrome.storage.local.set({registered: true});
  });
}

function sendRegistrationId(callback) {
  // Send the registration token to your application server
  // in a secure way.
}

chrome.runtime.onStartup.addListener(function() {
  chrome.storage.local.get("registered", function(result) {
    // If already registered, bail out.
    if (result["registered"])
      return;

    // Up to 100 senders are allowed.
    var senderIds = ["Your-Sender-ID"];
    chrome.gcm.register(senderIds, registerCallback);
  });
});

アプリまたは拡張機能が別のプロファイルや別の Chrome インスタンスにインストールされている場合は、それぞれが異なる登録トークンを受け取ります。

アプリや拡張機能では、gcm.unregister を呼び出して登録トークンを取り消すこともできます。登録解除は、アプリや拡張機能でこれ以上メッセージを受信したくない場合や、登録トークンが不正使用されている疑いがある場合など、ごく限られた状況下でのみ行うようにしてください。


function unregisterCallback() {
  if (chrome.runtime.lastError) {
    // When the unregistration fails, handle the error and retry
    // the unregistration later.
    return;
  }
}

chrome.gcm.unregister(unregisterCallback);

アプリや拡張機能は、ユーザーが明示的にアンインストールすると FCM サービスから自動的に登録解除されます。

ダウンストリーム メッセージを受信する

アプリサーバーからユーザーにメッセージを送信する場合、アプリサーバーは Firebase Cloud Messaging サーバーについてに記載されている 2 つの方法のいずれかを使用して FCM 接続サーバーに接続する必要があります。メッセージでは、そのユーザーに関連する登録トークンがすべて指定されます。FCM 接続サーバーがメッセージを受信すると、Chrome を実行しているアプリや拡張機能の全インスタンスに、そのメッセージと登録トークンの 1 つが送られます。アプリや拡張機能が 1 つの Chrome インスタンス上の複数プロファイルにインストールされている場合は、一意の登録トークンに基づいて各プロファイルで個別にメッセージを受け取ることができます。

サーバーからのメッセージは、chrome.gcm.onMessage イベントを介して配信されます。このイベントを受信するには、アプリや拡張機能にハンドラを登録する必要があります。


chrome.gcm.onMessage.addListener(function(message) {
  // A message is an object with a data property that
  // consists of key-value pairs.
});

Chrome が実行されている限り、拡張機能やアプリが実行されていない場合でも、スリープ状態が解除されてメッセージが配信されます。

アップストリーム メッセージを送信する

アプリサーバーからクライアントにプッシュ メッセージを配信することに加え、FCM ではクライアントからアプリサーバーにアップストリーム メッセージを送信することもできます。アプリサーバーは XMPP 接続サーバー プロトコルを実装する手順に記述されたとおり、FCM Cloud Connection Server に接続するよう設定しておく必要があります。

メッセージをアップストリームに送信するには、アプリや拡張機能で次の項目を含むオブジェクトを指定して chrome.gcm.send を呼び出してください。

  • キューに入らなかったり配信されなかったメッセージを識別するメッセージ ID。メッセージ ID は任意の種類の文字列で指定できますが、アプリや拡張機能の存続期間中は、たとえ再起動後であっても一意の値が保たれるようにすることをおすすめします。同じメッセージ ID を使うと、前のメッセージが上書きされてしまう可能性があります。自動インクリメント カウンタを使用してメッセージ ID が作成される場合、アプリや拡張機能では chrome.storage API を介してカウンタ値を保持し、アプリが再読み込みされる際にその値を復元する必要があります。
  • サーバーを識別する宛先 ID。This is the sender ID from the Firebase Console plus the suffix @gcm.googleapis.com.
  • 文字列と文字列による Key-Value ペアがリストされているデータ(合計 4 KB まで)。
  • 有効期間(TTL、省略可)。このプロパティの値は 0~86,400 秒(1 日)の期間にする必要があり、FCM がメッセージを保存して配信を試みる時間の最大の長さに該当します。このプロパティが設定されていない場合は、デフォルトで最大値に設定されます。TTL が 0 に設定されている場合、FCM は直ちにメッセージの配信を試みます。すぐに配信できなかった場合は、メッセージが破棄されます。

chrome.gcm.send に渡されたコールバックがランタイム エラーにならずに呼び出されても、そのメッセージが既に FCM 接続サーバーに配信されたことにはなりません。これは、それが配信の待ち行列に入れられたことを意味します。アプリや拡張機能では、chrome.runtime.lastError をチェックして処理する必要があります。返される可能性があるエラーコードについては、エラー リファレンスをご覧ください。

ネットワーク エラーなどの理由で TTL の指定期間内にメッセージが宛先に到達しなかった場合、chrome.gcm.onSendError が呼び出されます。アプリや拡張機能ではこのイベントをリッスンして、メッセージの再送信を試みるといった対応を行うことができます。返される可能性のあるエラーコードについては、エラー リファレンスをご覧ください。


// Substitute your own sender ID here. This is the Sender ID
// you got from the Firebase Console.
var senderId = "Your-Sender-ID";

// Make the message ID unique across the lifetime of your app.
// One way to achieve this is to use the auto-increment counter
// that is persisted to local storage.

// Message ID is saved to and restored from local storage.
var messageId = 0;
chrome.storage.local.get("messageId", function(result) {
  if (chrome.runtime.lastError)
    return;
  messageId = parseInt(result["messageId"]);
  if (isNaN(messageId))
    messageId = 0;
});

// Sets up an event listener for send error.
chrome.gcm.onSendError.addListener(sendError);

// Returns a new ID to identify the message.
function getMessageId() {
  messageId++;
  chrome.storage.local.set({messageId: messageId});
  return messageId.toString();
}

function sendMessage() {
  var message = {
    messageId: getMessageId(),
    destinationId: senderId + "@gcm.googleapis.com",
    timeToLive: 10.0.1,    // 1 day
    data: {
      "key1": "value1",
      "key2": "value2"
    }
  };
  chrome.gcm.send(message, function(messageId) {
    if (chrome.runtime.lastError) {
      // Some error occurred. Fail gracefully or try to send
      // again.
      return;
    }

    // The message has been accepted for delivery. If the message
    // can not reach the destination, onSendError event will be
    // fired.
  });
}

function sendError(error) {
  console.log("Message " + error.messageId +
      " failed to be sent: " + error.errorMessage);
}

詳細トピック

メッセージ削除イベント

FCM には、サーバーからクライアントに送信された折りたたみできないメッセージが 100 件まで保存されます。それ以降、すべてのメッセージは FCM から破棄され、イベント chrome.gcm.onMessagesDeleted が呼び出されてクライアントにメッセージの遅延が通知されます。アプリや拡張機能ではこれに応答して、破棄されたメッセージを復元するためにアプリサーバーと同期する必要があります。


chrome.gcm.onMessagesDeleted.addListener(messagesDeleted);

function messagesDeleted() {
  // All messages have been discarded from Firebase Cloud Messaging. Sync with
  // your application server to recover from the situation.
}

折りたたみできるメッセージ

FCM メッセージは、最新データをサーバーに問い合わせるようアプリや拡張機能に対して指示するため、込み入ったものになりがちです。FCM では、このような状況のために折りたたみできるメッセージを作成して、古いメッセージが新しいメッセージに置き換わるようにすることができます。折りたたみキーが提供され、同じユーザー宛ての複数のメッセージが FCM 接続サーバーのキューに入った場合は、折りたたみキーが指定されている最後のメッセージだけがアプリや拡張機能に配信されます。その結果、chrome.gcm.onMessage イベントに渡された message オブジェクトには collapseKey フィールドが含まれます。

エラー リファレンス

API 関数 chrome.gcm が呼び出されたときにエラーが発生する可能性があります。アプリや拡張機能では、chrome.runtime.lastError をチェックしてコールバックの詳細情報がないかどうか確認する必要があります。また、エラーコードもパラメータとして chrome.gcm.onSendError イベントに渡されます。

chrome.gcm エラーの概要は次のとおりです。

  • 無効なパラメータで関数が呼び出されました: chrome.gcm 関数が不正なパラメータで呼び出されたときに発生する可能性があります。
  • 非同期処理が保留中です: 前の関数に渡されたコールバックが呼び出されるまで待たずに、特定の chrome.gcm 関数が再び呼び出されたときに発生する可能性があります。
  • ネットワーク エラーが発生しました: インターネットが切断されるなどのネットワークの問題によって、FCM 接続サーバーが到達できなかった場合に発生する可能性があります。
  • サーバーエラーが発生しました: サーバーがビジー状態であるなどのサーバーの問題によって、FCM 接続サーバーが到達できなかった場合に発生する可能性があります。
  • 有効期間を超えました: 特定の有効期間内にメッセージを配信できなかったときに発生する可能性があります。
  • 不明なエラーが発生しました: 他の内部エラーが原因で発生する可能性があります。

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