DRYな備忘録

Don't Repeat Yourself.

Firebase Cloud Messaging(FCM)でより簡単にWebブラウザにPush通知を送るサンプル

前回、下記のエントリでProgressive Web Appにおけるそこそこ生のWeb-Push-Protocolについておおまかな仕組みを触れました

otiai10.hatenablog.com

ので、今回はFirebase Cloud Messagingを使って、もっと手軽にWebブラウザにPush通知を送るのをやってみた備忘録です。

公式ドキュメント

必要なもの

  • GCM Sender ID
    • ブラウザ(デバイス)側で、Subscriptionを発行するときに、このアプリケーションの所属を明らかにするために必要
    • WebPushProtocolにおけるApplicationServerPublicKeyをFirebaseがラップしている要素だと思えばよい
  • FCM Server Key
    • 自前サーバ側で、FCMを叩くときに、アプリケーションの所属と妥当性を明らかにするために必要
    • WebPushProtocolにおけるApplicationServerPrivateKeyをFirebaseがラップしている要素だと思えばよい

どっちもFirebase consoleで手に入る。

  1. Firebase consoleに行き、[プロジェクトを追加]する(図)
  2. [ウェブアプリにFirebaseを追加]を選択(3つ並んだ◯の右の赤いやつ)
  3. messagingSenderIdというのがあるので、これがGCM_SENDER_IDです
  4. つづいて、左上、[Overview]の隣の設定アイコンから[プロジェクトの設定]を選択
  5. 上部のタブのうち[クラウドメッセージング]を選択 6.サーバーキーというのがあるので、これがFCM_SERVER_KEYです

f:id:otiai10:20170622010233p:plain

やること

  • ブラウザのタブで動くmain.js
    • firebaseアプリケーションの初期化
    • messagingモジュールの初期化
      • 自動で/firebase-messaging-sw.jsをServiceWorkerとしてregisterしようとする
    • Notificationの許可と、DeviceToken取得できたら自前サーバにそれを送る
  • バックグラウンドで動き続けるfirebase-messaging-sw.js
    • ブラウザタブがactiveでないときにPush通知が来たときのハンドラを設定できる
  • 自前のサーバserver.js
    • ブラウザから送りつけられてきた各ユーザのDeviceTokenの保存
    • 何らかのきっかけでFCMのエンドポイントを叩く
      • payloadのtoというフィールドでPush通知を投げたい相手のDeviceTokenを指定する
    • もちろんjsである必要はない全く無い

うるせえ動くコード見せろ

ウッス

github.com

% git clone git@github.com:otiai10/firebase-messaging-sample.git
% cd firebase-messaging-sample
% GCM_SENDER_ID={上記の} \
FCM_SERVER_KEY={上記の(けっこう長い)} \
node server.js

こんな感じでうごく

f:id:otiai10:20170622022753p:plain

注意点・ハマったポイント

manifest.jsonのgcm_sender_idは"103953800507"

  • 問題: ブラウザのコンソールで「Messaging: Please change your web app manifest’s ‘gcm_sender_id’ value to ‘103953800507’ to use Firebase messaging. (messaging/incorrect-gcm-sender-id).」と叱られる
  • 原因: これは、実際にPush通知を送る主体はFirebaseのサーバなので、FirebaseのアプリケーションIDを登録する必要があるため
  • 解決: ハードコードで103953800507を指定する manifest.json

setBackgroundMessageHandlerで設定したハンドラが呼ばれてない

  • 問題: firebase-messaging-sw.jsにおいて、setBackgroundMessageHandlerを使ってハンドラを登録しているのにもかかわらず、ぜんぜん呼ばれてる気配が無い
  • 原因:
    • その1: ブラウザのタブがactiveな時は必ず、ブラウザタブのmain.jsにおけるmessaging.onMessageが呼ばれるので、ServiceWorkerには入らない
    • その2: これが上記で「癖がある」って言ったやつなんですけど、自前サーバ側でFirebase叩くときに、そのペイロード中にnotificationというフィールドのデータが入っていると、そのnotificationで指定したtitle,body,iconでNotificationが生成され、ServiceWorkerには入らない。ふしぎだね。
  • 解決: まずブラウザのタブを閉じる。そんで、サーバからのFCMへのリクエストのトップにnotificationというフィールドを含めない

雑感

  • 暗号化その他もろもろFirebaseがやってくれるので、やっぱり素でWeb-Push-Protocolに乗るより断然お手軽だった
  • 癖があるところとか、ほげほげKEYが多すぎて混乱するところとかはあるけども
  • 酒が弱くなってる。よいことだ。

DRYな備忘録として

Using Google App Engine

Using Google App Engine