はじめに
Mobile PushにFCMを使うことになったので、モバイルの知識がなくても出来るWeb Pushから始めることに。
ただ、執筆時点で推奨されているHTTP v1 APIでの使用にちょっとだけ苦労しました。
備忘録の意味も込めて手順を残しておきます。
FCM(Firebase Cloud Messaging)とは
今回はサンプルアプリの構築手順がメインですので、FCM自体の詳細な説明については参考リンクの記事に譲ります。
概要だけ書くと、FCMはFirebaseが提供するメッセージングサービスで、Android、iOS、WebブラウザなどにPush通知を飛ばすことができるようになります。
また、FCM APIへHTTPリクエストする際に事前登録したクライアントのトークンを指定することで、宛先を限定したPush通知が可能です。
Web Pushを試してみよう
今回のサンプルアプリ作成に使用した環境はこちら。
- Googleアカウント(Firebaseサービス利用のため)
- MacOS Monterey(v12.2.1)
- Webブラウザ(Chrome 99.0.4844.51)
- Node(v16.13.0)
Firebaseのプロジェクトを準備する
まずはFirebaseでFCMプロジェクトを作成。
Googleアカウントを使用してFirebaseにログインしたら、トップ画面でプロジェクトを作成。
プロジェクト名を入力すると、自動で一意のプロジェクトIDが割り当てられます。
この後Google Analyticsの有効/無効を任意に選択し、プロジェクトの作成を実行。
作成したプロジェクトの概要ページで</>
を選択し、Web Pushを使用するためのアプリを追加します。
アプリのニックネームを適当に設定。
SDKの追加方法で<script>タグを使用する
を選択するとconfig情報(firebaseConfig
)が表示されるので控えておきましょう。
Push通知に必要な秘密鍵は、プロジェクトの概要
の右にある⚙アイコンからプロジェクトの設定
→ サービス アカウント
タブと進み、Node.js
を選択した状態で新しい秘密鍵の生成
でDLしておきます。
ランダム文字列でファイル名が生成されますが、分かりやすいようここではservice-account.json
としておきます。
またCloud Messaging
タブのウェブ設定にあるGenerate key pair
でGCPサービス外へのPush通知に使用するVAPIDを生成し、こちらも控えておきましょう。
FCMからクライアントへトークンを発行する
FCMからクライアントのトークンを取得するためのサンプルアプリを実装します。
公式のサンプルをCloneし、下のようにソースを適宜書き換えます。(差分のみ記載)
なお、MY_…
は先ほど控えた設定値に書き換えます。
firebase-messaging-sw.js
はService Workerと言い、クライアントがバックグラウンドの際に実行される処理を定義します。
今回はサンプルのonBackgroundMessage
をそのまま使用し、バックグラウンドの時にはPush通知がOS固有の通知センターに表示されるようにします。
- <script src="/__/firebase/9.6.7/firebase-app-compat.js"></script>
- <script src="/__/firebase/9.6.7/firebase-messaging-compat.js"></script>
- <script src="/__/firebase/init.js"></script>
+ <script src="https://www.gstatic.com/firebasejs/9.6.8/firebase-app-compat.js"></script>
+ <script src="https://www.gstatic.com/firebasejs/9.6.8/firebase-firestore-compat.js"></script>
+ <script src="https://www.gstatic.com/firebasejs/9.6.8/firebase-auth-compat.js"></script>
+ <script src="https://www.gstatic.com/firebasejs/9.6.8/firebase-messaging-compat.js"></script>
:
:
<script>
+ firebase.initializeApp({
+ apiKey: "MY_API_KEY",
+ authDomain: "MY_AUTH_DOMAIN",
+ projectId: "MY_PROJECT_ID",
+ storageBucket: "MY_STORAGE_BUCKET",
+ messagingSenderId: "MY_MESSAGING_SENDER_ID",
+ appId: "MY_APP_ID",
+ measurementId: "MY_MEASUREMENT_ID",
+ });
:
:
function resetUI() {
clearMessages();
showToken("loading...");
// Get registration token. Initially this makes a network call, once retrieved
// subsequent calls to getToken will return from cache.
messaging
- .getToken({ vapidKey: "<YOUR_PUBLIC_VAPID_KEY_HERE>" })
+ .getToken({ vapidKey: "MY_PUBLIC_VAPID_KEY_HERE" })
- importScripts("/__/firebase/9.2.0/firebase-app-compat.js");
- importScripts("/__/firebase/9.2.0/firebase-messaging-compat.js");
- importScripts("/__/firebase/init.js");
+ importScripts("https://www.gstatic.com/firebasejs/9.6.8/firebase-app-compat.js");
+ importScripts("https://www.gstatic.com/firebasejs/9.6.8/firebase-messaging-compat.js");
:
:
+ firebase.initializeApp({
+ apiKey: "MY_API_KEY",
+ authDomain: "MY_AUTH_DOMAIN",
+ projectId: "MY_PROJECT_ID",
+ storageBucket: "MY_STORAGE_BUCKET",
+ messagingSenderId: "MY_MESSAGING_SENDER_ID",
+ appId: "MY_APP_ID",
+ measurementId: "MY_MEASUREMENT_ID",
+ });
ローカルサーバを立ち上げてindex.htmlにアクセスすると、トークン取得用の簡易アプリが表示されます。
しばらくするとFCMに登録したトークンが表示されるはずです。
このトークンも後で使用するので控えておきましょう。
Push通知を送信する
Push通知を送信するための仮想サーバプログラムを実装します。
先ほどDLしたservice-account.json
はこのサーバプログラムのルート直下に置いておきます。
MY_REGISTER_TOKEN
は先ほど控えたクライアントの登録トークン、YOUR_APP_ID
はFCMのプロジェクトIDに書き換えます。
var google = require("googleapis");
var https = require("https");
function getAccessToken() {
return new Promise(function (resolve, reject) {
const key = require("./service-account.json");
const jwtClient = new google.Auth.JWT(
key.client_email,
null,
key.private_key,
["https://www.googleapis.com/auth/firebase.messaging"],
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
reject(err);
return;
}
postPushMessage(tokens.access_token);
});
});
}
function postPushMessage(accessToken) {
const data = JSON.stringify({
message: {
token:
"MY_REGISTER_TOKEN",
notification: {
title: "フォアグラウンド通知のタイトルだよ。",
body: "フォアグラウンド通知の本文だよ。",
},
},
});
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + accessToken,
},
body: data,
};
const url =
"https://fcm.googleapis.com/v1/projects/YOUR_APP_ID/messages:send";
const request = https.request(url, options, (response) => {
console.log(`statusCode: ${response.statusCode}`);
});
request.write(data);
request.end();
}
getAccessToken();
これで準備完了です。
実行してリクエストが成功することを確認します。
$ node ./postPushMessage.js
statusCode: 200
挙動確認
スクリプトを実行した際にブラウザがフォアグラウンドかバックグラウンドかで挙動が変わります。
フォアグラウンドの時には通知を受け取った旨がサンプルアプリに表示されます。
バックグラウンドの時には通知センターに通知が表示されます。
お疲れ様でした。
旧HTTP APIと何が変わったの?
冒頭でも言いましたが、通知メッセージについては旧来のHTTP APIと現行のHTTP v1 APIで色々と仕様が異なっており、公式ドキュメントで差分を見ながら手探りで実装する必要がありました。
特に以下の違いを見つけるのに少々時間がかかってしまいました。
- Push通知リクエストの向き先エンドポイントが異なる
POST https://fcm.googleapis.com/fcm/send
POST https://fcm.googleapis.com/v1/projects/YOUR_APP_ID/messages:send
- Push通知リクエスト用の認証には生成後不変なサーバーキーではなく一時的なトークンを使用する
- Push通知リクエスト用のBodyも書き方が異なる
{
"to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification": {
"title": "Portugal vs. Denmark",
"body": "great match!"
},
}
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
},
}
}
参考になれば幸いです。