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

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


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

## Firebase Cloud Messagingの設定

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

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

## Messageの受信設定

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

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

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

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

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

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

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


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

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


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

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


### Messageの受け取り

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

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

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

```javascript
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の初期化、メッセージングオブジェクトの生成を行います。

```javascript
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",
      }
   }
}
```

送信するとブラウザ側でメッセージを受け取り通知してくれます。
<img width="623" alt="スクリーンショット 2019-07-31 14.13.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442896/e93fb02e-e589-4854-ed26-df26252aa2e2.png">


## スマートフォンで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です。

```javascript
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をインポート

```javascript
import axios from 'axios'
```

APIの処理を実装

```javascript
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を叩くとスマホに通知が届くことが確認できます。

![Screenshot_20190731-132803_Nova Launcher.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442896/5306ed19-acb1-10a7-e127-c136d3525c4d.jpeg)



## まとめ

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