Android でのトピック メッセージング

パブリッシュ / サブスクライブ モデルに基づく FCM トピック メッセージングでは、特定のトピックにオプトインした複数の端末にメッセージを送信できます。必要に応じて作成したトピック メッセージを FCM がルーティング処理し、確実に正しい端末にメッセージを配信します。

たとえば、地域の天気予報アプリのユーザーは、「荒天警報」のトピックにオプトインし、暴風雨警報指定地域の通知を受信できます。スポーツアプリのユーザーは、お気に入りのチームの実況ゲームスコアの自動更新に登録できます。

トピックに関する留意点を以下に示します。

  • トピック メッセージングは、アプリごとに無制限のトピックとサブスクリプションをサポートします。
  • 現在、トピック メッセージ ペイロードは 2 KB に制限されています。
  • トピック メッセージングは、ニュース、天気、その他の広く入手可能な情報コンテンツに最適です。
  • トピック メッセージは、レイテンシではなくスループットに対して最適化されます。単一の端末または端末の小グループに高速かつ安全に配信する場合は、トピックではなく登録トークンをメッセージの宛先としてください
  • 各ユーザーの複数の端末にメッセージを送信する必要がある場合は、そのようなユースケース向けの端末グループ メッセージングを検討してください。

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

クライアント アプリを既存のトピックに登録することも、新しいトピックを作成することもできます。クライアント アプリを新しいトピック名(Firebase プロジェクトにまだ存在していないトピック名)に登録すると、その名前の新しいトピックが FCM に作成され、その後すべてのクライアントはそのトピック名に登録できるようになります。

トピックに登録する場合、クライアント アプリは、FCM トピック名で Firebase Cloud Messaging subscribeToTopic() を呼び出します。

FirebaseMessaging.getInstance().subscribeToTopic("news");

登録解除する場合、クライアント アプリはトピック名で Firebase Cloud Messaging unsubscribeFromTopic() を呼び出します。

サーバーでトピック登録を管理する

Instance ID API を利用して、サーバー側から基本的なトピック管理タスクを行うことができます。クライアント アプリ インスタンスの登録トークンを取得すると、次の操作を行えます。

メッセージを受信して処理する

FCM は、他のダウンストリーム メッセージと同じようにトピック メッセージを配信します。

メッセージを受信するには、FirebaseMessagingService を拡張したサービスを使用します。このサービスは onMessageReceived コールバックと onDeletedMessages コールバックをオーバーライドする必要があります。メッセージは受信から 10 秒以内に処理されるようにします。10 秒経過すると、Android では実行が保証されず、いつでもプロセスが終了される可能性があります。メッセージの処理にもう少し時間が必要な場合は、Firebase Job Dispatcher を使用してください。

onMessageReceived はほとんどのメッセージ タイプに用意されていますが、次の例外があります。

  • アプリがバックグラウンドで動作しているときに配信された通知メッセージ。この場合、通知は端末のシステムトレイに配信されます。通知をユーザーがタップすると、デフォルトではアプリのランチャーが開きます。

  • 通知とデータ ペイロードの両方を含む、バックグラウンドおよびフォアグラウンドのメッセージ。この場合、通知は端末の通知領域(システムトレイ)に配信され、データ ペイロードはランチャー アクティビティのインテントの追加部分で配信されます。

要約:

アプリの状態 通知 データ ペイロード 両方
フォアグラウンド onMessageReceived onMessageReceived onMessageReceived
バックグラウンド システムトレイ onMessageReceived 通知: システムトレイ
インテントの追加部分にあるデータ
メッセージ タイプについて詳しくは、通知とデータ メッセージをご覧ください。

アプリのマニフェストの編集

FirebaseMessagingService を使用するには、アプリのマニフェストに次の設定を追加する必要があります。

<service
    android:name=".MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

通知の外観をカスタマイズするためのデフォルト値を設定することもお勧めします。通知ペイロード内に同等の値が設定されていなかった場合に適用されるカスタム デフォルト アイコンとカスタム デフォルト カラーを指定できます。

カスタム デフォルト アイコンとカスタムカラーを設定するには、次の行を application タグに追加します。

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Android には、以下の場合にカスタム デフォルト アイコンが表示されます。

  • Notifications Composer から送信されたすべての通知メッセージ。
  • 通知ペイロード内にアイコンが明示的に設定されていない通知メッセージ。

Android では、以下の場合にカスタム デフォルト カラーが使用されます。

  • Notifications Composer から送信されたすべての通知メッセージ。
  • 通知ペイロード内にカラーが明示的に設定されていない通知メッセージ。

カスタム デフォルト アイコンが設定されず、通知ペイロード内にもアイコンが設定されていない場合は、Android では白色でレンダリングされたアプリケーション アイコンが表示されます。

onMessageReceived のオーバーライド

FirebaseMessagingService.onMessageReceived メソッドをオーバーライドすれば、受信した RemoteMessage オブジェクトに基づいて操作を行い、メッセージ データを取得することができます。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // ...

    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

onDeletedMessages のオーバーライド

場合によっては、FCM からメッセージが配信されないことがあります。これは、特定の端末が接続されたときにその端末にまだ配信されていないアプリのメッセージが多すぎる(100 件を超えている)場合や、端末が 1 か月以上 FCM に接続されていない場合に起こります。このような場合、FirebaseMessagingService.onDeletedMessages() へのコールバックを受け取ることがあります。アプリ インスタンスがこのコールバックを受け取った場合は、アプリサーバーとの完全な同期を実行する必要があります。過去 4 週間以内にその端末のアプリにメッセージを送信していない場合、onDeletedMessages() は呼び出されません。

バックグラウンド アプリの通知メッセージの処理

アプリがバックグラウンドで動作しているとき、Android ではシステムトレイに通知メッセージが送られます。ユーザーが通知をタップすると、デフォルトでアプリ ランチャーが開きます。

通知とデータ ペイロードの両方を含むメッセージ(および Notifications コンソールから送信されたすべてのメッセージ)がここに含まれます。通知は端末の通知領域(システムトレイ)に配信され、データ ペイロードはランチャー アクティビティのインテントの追加部分で配信されます。

ビルド送信リクエスト

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

複数のトピックの組み合わせに送信する場合、アプリサーバーは condition キーに、対象のトピックを指定するブール条件を設定します。たとえば、TopicA と、TopicBTopicC のいずれかに登録された端末にメッセージを送信する場合は、次のようになります。

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

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

  • TopicA と TopicB
  • TopicA と TopicC

トピックの条件では、かっこの使用と、式ごとに 2 つの演算子の使用がサポートされています。

アプリサーバーのキーの詳細については、選択した接続サーバー プロトコル(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",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

「犬」や「猫」のトピックに登録された端末に送信します。

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

トピック HTTP レスポンス

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

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

トピック XMPP メッセージ

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

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

「犬」や「猫」のトピックに登録された端末に送信します。

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

トピック XMPP レスポンス

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

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

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

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

次のステップ

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

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