Firebase Cloud Messagingでトピックを使ってメッセージを送信してみた(Firebase Admin Node.js SDK)

2022.06.05

こんにちは、CX事業本部 IoT事業部の若槻です。

前回のエントリでは、Firebase Cloud Messagingで、指定したRegistration Tokenのクライアントへ直接メッセージ送信を行いました。

今回は、Firebase Cloud Messagingでトピックを使ってメッセージ送信をしてみました。

やってみた

前提

Firebase Admin Node.js SDKを使用します。

環境は次のようになります。

$ npm ls typescript ts-node --depth=0
hoge-project@0.1.0
├── ts-node@9.1.1
└── typescript@3.9.10
└── firebase-admin@10.2.0
$ node --version
v14.17.0

また次のエントリの内容のFlutter Web Appが作成済みである前提とします。このアプリへメッセージを送信できるようにします。

private keyの取得

Firebaseのコンソールで、[Project settings]-[Service account]-[Firebase Admin SDK]で[Generate new private key]をクリックします。

[Generate key]をクリックすると、private keyが記載されたservice account file(<project>-firebase-adminsdk-xxxx-xxxxxxxx.json)がダウンロードされます。

ダウンロードされたservice account fileをプロジェクトのルートなどに配置します。

スクリプト作成

testTopicというトピックのサブスクライブ(トピックへのRegistration Tokenの登録)を行うスクリプトです。トピックはサブスクライブ時に未作成なら作成が行われます。

subscribe-topic.ts

import * as firebaseAdmin from 'firebase-admin';

const REGISTRATION_TOKEN = process.env.REGISTRATION_TOKEN || ''; //文字列または文字列リストで指定可能
const TOPIC_NAME = 'testTopic';

firebaseAdmin.initializeApp();

const subscribeToTopic = async (): Promise<void> => {
  await firebaseAdmin
    .messaging()
    .subscribeToTopic(REGISTRATION_TOKEN, TOPIC_NAME);
};

subscribeToTopic();

トピックへメッセージを送信するスクリプトです。

send-message.ts

import * as firebaseAdmin from 'firebase-admin';

const TOPIC_NAME = 'testTopic';

firebaseAdmin.initializeApp();

const sendMessage = async (): Promise<void> => {
  const params = {
    notification: {
      title: 'テストタイトル',
      body: 'テスト本文',
    },
    topic: TOPIC_NAME,
  };

  await firebaseAdmin.messaging().send(params);
};

sendMessage();

動作確認

前回作成したFlutter Web Appを起動し、デバッグコンソールからRegistration Tokenを取得します。

service account fileのパスおよびRegistration Tokenを環境変数に指定します。

export GOOGLE_APPLICATION_CREDENTIALS=<GOOGLE_APPLICATION_CREDENTIALS>
export REGISTRATION_TOKEN=<REGISTRATION_TOKEN>

スクリプトを実行します。

$ npx ts-node subscribe-topic.ts
$ npx ts-node send-message.ts

クライアントでメッセージが受信できました!

トピックをConditionで指定する

メッセージの送信でトピックをConditionで指定することも可能です。

OR条件||とAND条件&&を使用して、次のようにサブスクライブしているトピックの条件を指定します。

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

この条件文字列をsend()conditionパラメータを指定します。

conditional-send-message.ts

import * as firebaseAdmin from 'firebase-admin';

const TOPIC_CONDITION = process.env.TOPIC_CONDITION || '';

firebaseAdmin.initializeApp();

const sendMessage = async (): Promise<void> => {
  const params = {
    notification: {
      title: 'テストタイトル2',
      body: 'テスト本文2',
    },
    condition: TOPIC_CONDITION,
  };

  await firebaseAdmin.messaging().send(params);
};

sendMessage();

まずトピックの条件をtestTopicまたはtestTopic2として、メッセージ送信スクリプトを実行します。

$ export TOPIC_CONDITION="'testTopic' in topics || 'testTopic2' in topics"
$ npx ts-node conditional-send-messagee.ts

testTopicをサブスクライブしているクライアントで受信できました!

次にトピックの条件をtestTopicおよびtestTopic2として、メッセージ送信スクリプトを実行します。

$ export TOPIC_CONDITION="'testTopic' in topics && 'testTopic2' in topics"
$ npx ts-node conditional-send-messagee.ts

すると今度はtestTopicのみをサブスクライブしているクライアントへはメッセージは送信されませんでした!

おわりに

Firebase Cloud Messagingでトピックを使ってメッセージ送信をしてみました。

クライアント側ではトピックのサブスクライブを行い、サーバー側ではトピックへのメッセージ送信をする分担とすれば、直接送信する場合に比べてシステムの構成がシンプルになりそうだと思いました。

参考

以上