そーす

I'm a programmer in Fukuoka. Please contact me saubre.app[at]gmail.com or Twitter DM.

Firebase Cloud Messagingを使ってWebサイトでPush通知を受け取る

仕事でReact SPAにPush通知を実装することになったので備忘録。

Firebase Cloud Messaging(以下FCM)をWebにやるにはHttpsに対応のサイトじゃないとだめなので、Firebase Hostingで構築するところまでを記載します。

Firebaseの説明はありません。

Firebase Hostingの準備

先にFirebase Hostingを使ってサイトを作る準備をします。

Firebaseのプロジェクトを作成する

Firebaseのアカウントを持ってないならば作りましょう。

firebase.google.com

プロジェクトを作ります。

f:id:saburesan:20170817224342p:plain

Command Line Toolsのインストール

github.com

Firebaseをコマンドで扱うためのツールです。Firebase Hostingを使う時に使用します。

npm i -g firebase-tools

インストールが完了したらログインします。

firebase login

ブラウザが開きますので連携を許可しましょう。

Firebase Hostingのプロジェクトの初期化

適当に今回プロジェクトを作成するディレクトリを作成します。

そこで以下のコマンドで初期化します

firebase init

Firebaseのどのサービスの初期化か聞かれますので一番したのHostingを選びましょう

f:id:saburesan:20170818134047p:plain

すると、プロジェクトの選択があるので、最初に作ったプロジェクトを選択します。

初期化は以上です。

下記の2つのファイルが作成されます。

.firebaserc
firebase.json

firebase.jsonは空のJSONオブジェクトしか入ってないと思います。

リファレンスでは

アプリを初期化する際、公開ルートとして使用するディレクトリについて確認を求められます(デフォルトは「public」)。その時点で公開ルート ディレクトリに有効な index.html ファイルがない場合、自動的にファイルが作成されます。

とありますが、私の環境(バージョン?)では聞かれなかったので手動で公開ルートを設定します。

とりあえずpublicにしましょう。

{
  "hosting": {
    "public": "public"
  }
}

あとはpublicフォルダを作ってindex.htmlを仕込んでデプロイします。

f:id:saburesan:20170818135253p:plain

ちなみに、デプロイ前の確認としてローカルサーバを建てる機能もあります。

firebase serve
firebase deploy
=== Deploying to '#####'...

i  deploying hosting
i  hosting: preparing public directory for upload...
✔  hosting: 1 files uploaded successfully
i  starting release process (may take several minutes)...

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/#####/overview
Hosting URL: https://#####.firebaseapp.com

Hosting URLをブラウザで開くとちゃんとデプロイされてるのが確認出来ます。

FCMの設定

ブラウザからプロジェクトを開くとウェブアプリにFirebaseを追加というボタンがあるので

クリックすると設定のスクリプトが書いてあるのでそれをコピペしてindex.htmlに貼り付けましょう。

通知の許可を取るまではローカルサーバでも大丈夫です。

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>FCM Sample</title>
</head>

<body>
  <script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
  <script>
    // Initialize Firebase
    var config = {
      apiKey: ###
      authDomain: ###,
      databaseURL: ###,
      projectId: ###
      storageBucket: ###,
      messagingSenderId: ###,
    };
    firebase.initializeApp(config);
  </script>
</body>

</html>

これでプロジェクトの初期設定が完了です。

ServiceWorkerの作成

firebase-messaging-sw.js

FCMはルートディレクトリにあるfirebase-messaging-sw.jsというファイルをServiceWorkerに読み込ませます。

なので、このファイルをpublic以下に作成して中身を以下にします。

importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-messaging.js');

firebase.initializeApp({
  messagingSenderId: "###", // index.htmlにあるconfigのmessagingSenderIdと同じもの
});

const messaging = firebase.messaging();

manifest.json

manifest.jsonもpublic以下に作成します。manifest.jsonの詳しい説明はこちら

ウェブアプリ マニフェスト  |  Web  |  Google Developers

とりあえず今回は中身を以下にします。

{
  "gcm_sender_id": "103953800507"
}

gcm_sender_idは固定値で、全ての環境で同じ値を使います。

通知の許可を取る

次にユーザに通知を受け取るかどうかの許可を取ります。

    firebase.initializeApp(config);

    const messaging = firebase.messaging();
    messaging.requestPermission()
      .then(() => console.log('granted'))
      .catch(e => console.log(e));

これで実行すると通知の許可を取るダイアログが表示されます。

f:id:saburesan:20170818164215p:plain

InstanceIDトークンの取得

InstanceIDとはFirebaseのプロジェクトごとにユーザに割り当てられるIDのことです(多分)

それを元にしたトークンを使って個人ユーザにメッセージを送信することができます。

   messaging.requestPermission()
      .then(() => messaging.getToken())
      .then((token) => console.log(token))
      .catch(e => console.log(e));

Push通知はサーバから送ると思うのでこの時点でtokenをサーバに送りましょう。

メッセージの受信設定

フォアグラウンド通知(サイトを開いている状態)を受け取るためには以下の方法で受け取れます。

    messaging.requestPermission()
      .then(() => messaging.getToken())
      .then((token) => {
        console.log(token);
        messaging.onMessage(payload => alert(JSON.stringify(payload)));
      })
      .catch(e => console.log(e));

Push通知を送ってみる

ではPush通知を送ってみましょう。

送るのに必要なのはFirebaseプロジェクトのサーバーキーとInstanceIDトークンです。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key="Firebaseプロジェクトのサーバーキー"

{ "notification": {
    "title": "Hello",
    "body": "body",
    "click_action" : "http://saburesan.hatenablog.com/"
  },

  "to" : "// InstanceIDトークン"
}

フォアグラウンド通知(サイトを開いている状態)

f:id:saburesan:20170818172817p:plain

バックグラウンド通知(サイトが開かれていない状態)

f:id:saburesan:20170818173244p:plain

通知のpayloadを

"notification : {
   "title: " string, // 通知のタイトル
   "body": string, // 通知の本文
   "click_action": string, // タップした時に開きたいリンク
   "icon": string // 通知のアイコンに設定したい画像のパス
}

の形式にしておくと上記のスクリーンショットのように勝手に設定されます。

これでPush通知の基本的な実装は終わりです。

Topicsの購読

Firebaseには複数のユーザに同時にPushを送るTopicsという機能があります。

そのTopicsを購読するには以下のようにしてIID_TOKEN, TOPIC_NAME, PROJECT_SERVER_KEYを用いてリクエストを送る必要ことで購読することが出来ます。

fetch(`https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME`, {
    method: 'POST',
    headers: {
      Authorization: PROJECT_SERVER_KEY,
    },
  }),

まとめ

纏まってない。