Firebase Cloud Messaging(FCM)はモバイルアプリケーションやWebアプリケーションにプッシュ通知を送信できるサービスです。以前はデバイストークンをまとめて指定して一度に複数の端末にプッシュ通知を送信することができましたが今はできません。素朴に任意の複数の端末に通知を送る場合、通信をすること自体に時間がかかるオーバーヘッドが問題となり処理の完了が非常に遅くなります。これに対処した複数端末に通知を送る方法を紹介します。
FCMにはトピックという仕組みがあります。任意のトピックには任意のデバイストークンが紐づき、トピックに対してメッセージを送ると、そのトピックに属するデバイス全てに通知が送信されます。この仕組みを利用すると次の流れで任意の複数端末にプッシュ通知を送れます。
- 一時的なトピックAを作る
- トピックAに通知を送りたい端末のデバイストークンを紐づける
- トピックAにメッセージを送る
- トピックAを削除する
PHPでFCMを扱えるライブラリの一つにkreait/firebase-phpというものがあります。この記事ではこれを扱います。
kreait/firebase-php: Unofficial Firebase Admin SDK for PHP
実装コード例が次です。設定符の読み出しとランダム文字列の生成はLaravelを使ってます。特別Laravelである必要はないので環境に応じて適宜変更します。
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\CloudMessage;
use Illuminate\Support\Str;
// Firebase Messagingを初期化
$factory = (new Factory())->withServiceAccount(config('firebase.projects.app.credentials.file'));
$fcmClient = $factory->createMessaging();
// 一時的にトピックを作成してメッセージを送信するためのトピック名
$temporaryTopic = 'temp_topic_' . strtolower(\Str::random());
try {
// トークンを一時的なトピックにサブスクライブ
$fcmClient->subscribeToTopic($temporaryTopic, $registrationTokens);
// メッセージを作成。詳細なフォーマットは下記リンクを参照
// @see https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?hl=ja
$message = CloudMessage::fromArray([
'topic' => $temporaryTopic, // 送信先のトピック名
'data' => [
'title' => '件名',
'body' => '本文',
],
]);
// メッセージを送信
$fcmClient->send($message);
} catch (\Throwable $e) {
// 省略
} finally {
// 一時的なトピックからトークンをアンサブスクライブ
$fcmClient->unsubscribeFromTopic($temporaryTopic, $registrationTokens);
}
少々時間はかかりますが一つ一つ送るよりずっと早いです。何より送信先の数に比例して処理時間が延びるような事態にならないのがいいです。