Nuxt.js + Firebase + Netlifyでログイン認証+push通知機能のあるPWAを作る(その3) - Push通知受け取り&Functionsを使ってRealtimeDatabaseにトークンを保存


これまでの記事
- 第1回
Nuxt.js + Firebase + Netlifyでログイン認証+Push通知機能のあるPWAを作る(その1) - 環境構築(Nuxt、Firebase設定、Netlifyホスティング、自動デプロイ) - Qiita
- 第2回
Nuxt.js + Firebase + Netlifyでログイン認証+push通知機能のあるPWAを作る(その2) - ログイン処理、ユーザ登録、認証処理実装 - Qiita

今回の最後の目標のプッシュ通知をFirebase Cloud Messagingを使用して実装します。

Firebase Cloud Messagingの設定

nuxt.config.jsに以下の設定を追加

manifest: {
  gcm_sender_id: '103953800507' // このgcm_sender_idは固定値
} 

Messageの受信設定

発行されたメッセージを受け取るために必要な処理は

  • プッシュ通知の許可
  • トークンの発行
  • メッセージの受け取り処理
  • ServiceWorkerの設定

が必要になるので、それぞれ実装してみる

プッシュ通知の許可とトークンの発行

ログイン後に遷移するindex.jsに処理を実装していきます。
index.jsのcreated()にメッセージングのオブジェクトを生成します。

created() {
  const messaging = firebase.messaging()
}

生成したメッセージングオブジェクトから通知許可とトークンの取得を行います。
通知許可はrequestPermissionで行います。

created() {
  const messaging = firebase.messaging()
  messaging.requestPermission()
}

ここまでで保存し、リロードすると通知の許可を求められます。
通知の許可を有効にするとPromiseが返ってくるのでこのタイミングでトークンの発行を行います。

created() {
  const messaging = firebase.messaging()
  messaging.requestPermission()
    .then(() => {
      return messaging.getToken()
    })
    .then((token) => {
      console.log(token)
    })
    .catch((error) => {
      console.log(error)
    })
}

コンソールを確認するとトークンが取得できていることが確認できます。

Messageの受け取り

最後に発行されたメッセージを受け取る処理を実装します。
メッセージはonMessageで受け取ることができます。

messaging.onMessage((payload) => {
  console.log('message: ', payload)
})

payloadから通知のタイトルやボディなどを取得することができます。
created()の実装は最終的に以下のようになります。

created() {
  const messaging = firebase.messaging()
  messaging.requestPermission()
    .then(() => {
      return messaging.getToken()
    })
    .then((token) => {
      console.log(token)
    })
    .catch((error) => {
      console.log(error)
    })
  messaging.onMessage((payload) => {
    console.log('message: ', payload)
  })
}

Service Workerの設定

このままではアプリがonMessageイベントの受信ができません。
これを可能にするためにfirebase-messaging-sw.jsでFirebaseのメッセージングService Workerを定義する必要があります。

staticディレクトリ内にfirebase-messaging-sw.jsを作成。

touch static/firebase-messaging-sw.js

ここでFirebase SDKのインポートとSenderIdを指定しFirebaseの初期化、メッセージングオブジェクトの生成を行います。

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

firebase.initializeApp({
  messagingSenderId: <MESSAGING_SENDER_ID>
})

const messaging = firebase.messaging()

ここまででメッセージの受信設定は完了です。

実際にプッシュ通知を受け取ってみる

Postmanなどを使って直接通知を送り、メッセージを受け取ってみます。
Authorizationには設定=>クラウドメッセージングのプロジェクト認証情報に記述されているサーバーキーを設定します。
トークンは取得したトークンをそのまま設定します。

POST https://fcm.googleapis.com/fcm/send

Content-Type: application/json
Authorization: key=<SERVER KEY>

{
  "message":{
    "token" : <TOKEN>,
    "notification" : {
      "body" : "This is an FCM notification message!",
      "title" : "FCM Message",
      }
   }
}

送信するとブラウザ側でメッセージを受け取り通知してくれます。

スマートフォンでPWAとして通知を受け取る

次はスマートフォン側でPWAとしてアプリを追加し、通知を受け取ってみます。
Web上では開発者ツールからトークンが確認できましたが、スマホからはログが見れません。

それでFirebaseのFucntionsを利用し、RealtimeDatabaseにトークンを書き込む処理を実装し、そのトークンを利用して通知を行ってみます。

Firebase Functions

まずはFunctionsの実装、デプロイを行います。
作業中のディレクトリとは別のディレクトリを作成し移動します。
今回はbackendというディレクトリで進めます。

ログインと初期化

backendディレクトリに移動したらまずFirebaseにログインします。

firebase login

ログインができたら初期化を行います。

firebase init

どのサービスを使用するか聞かれますが、今回はFunctionsのみの選択になります。

APIの実装

完了したらfunctionsディレクトリが生成されます。
functionsディレクトリ内のindex.jsにAPIの実装を行います。

実装に掛かる前にCORSを許可するnpmパッケージをインストールします。

npm install cors

完了したらAPIを実装していきます。
リクエストのクエリをDBに書き込んでいくだけのシンプルなAPIです。

const functions = require('firebase-functions')
const cors = require('cors')({origin: true})
const admin = require('firebase-admin')
admin.initializeApp()

exports.addMessage = functions.https.onRequest((request, response) => {
  cors(request, response, async () => {
    const token = request.query.token
    await admin.database().ref('/messages').push({token: token})
    response.status(200).send({status: 'success'})
  })
})

addMessageがAPIのリソース名となります。
関数内をcorsでラップすることでCORSを許可できます。

ここまで実装できたらデプロイします。

firebase deploy --only functions

デプロイに成功するとAPIのURIが生成され、表示されます。

アプリにトークン送信処理を実装

先ほど作成したAPIをアプリに組み込みトークンをDBに登録するように実装する。

pages/index.jsの内のトークンを受け取ったタイミングでAPIを叩くようにする。

まずはAxiosをインポート

import axios from 'axios'

APIの処理を実装

messaging
  .requestPermission()
  .then(() => {
    return messaging.getToken()
  })
  .then((token) => {
    // --------- 追加 ---------- //
    const url = `https://<Domain>/addMessage?token=${token}`
    axios.get(url)
    // ------------------------ //
  })
  .catch((error) => {
    console.log(error)
  })

PWAでPush通知を受け取る

先ほどの変更をNetlifyにデプロイする。
スマートフォンからデプロイ先のURLを開きホーム画面に追加を行う。
ログインを行い、ホーム画面にアプリをバックグラウンドの状態にする。
その状態でPush通知の送信APIを叩くとスマホに通知が届くことが確認できます。

まとめ

今回を含めて3回に分けてやってきましたが、一番感じるのはFirebaseはどの機能もサクッと使えるのでかなり便利だなと思いました。
Push通知はアプリがフォアグラウンドにいるときはvue-notificationsなどを使って自前で実装しないとダメみたいですね。
フォアグラウンドでもピョコンっと通知が出てくるものと思ってました、、
また現状ログイン後に遷移するトップページに訪れるたびにトークンをDBに送ってるのでそのあたりも改善の余地ありです。
PWAって需要があるのかないのかよくわからないっていうのが正直なところですが気軽にアプリっぽくできるのはメリットですね。
今後PWAが増えていくことに期待です。