Nuxt.js＋Push7でPWAアプリとプッシュ通知を実装する

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/f491f75d-69ef-cec3-438c-d30e38e6d61d.png)

Nuxt.jsを使うと、比較的簡単にPWA対応のサイトを作ることができます。
ただ、PWA対応と一言で言っても、PWAが指す機能は様々なものがあります。

- オフラインキャッシュ
- ホームスクリーン追加
- プッシュ通知
- カメラ
- 決済機能
- etc

iOSではAndroidと比べてPWAの対応が遅く、キャッシュ以外はあまり使うことがなかったのですが、
最近iPhoneからPixel4に機種変更したこともあり、手元の環境で色々とPWAを試すことができるようになったので、
色々実装して遊んでみました。


今回は、比較的簡単に実装ができる、

- オフラインキャッシュ
- ホームスクリーン追加
- プッシュ通知

を[Nuxt.js](https://ja.nuxtjs.org/)と[Push7](https://push7.jp/)というサービスを使って、実装してみたいと思います。

なお、今回作成したサンプルは以下のURLにアップしています。
https://nuxtpwa.netlify.com/
https://github.com/chieeeeno/nuxt_webpush_sample

## オフラインキャッシュ対応
Nuxt.jsでは公式のモジュールでPWAのモジュールが提供されており、 `create-nuxt-app` で雛形を作る時にPWAのモジュールを追加することで、ほぼコーディング無しでオフライン対応を行うことが可能です。

`create-nuxt-app`を実行した時にいろいろ聞かれる質問で、 `Progressive Web App (PWA) Support`にチェックを入れておきます。

```
? Choose Nuxt.js modules
 ◯ Axios
❯◉ Progressive Web App (PWA) Support
 ◯ DotEnv
```

そうすることで、`@nuxtjs/pwa` のインストールと `nuxt.config.js` にモジュールの記述を追加してくれます。
あとは、 `nuxt build` を実行すると、オフラインキャッシュに必要な `Service Worker`の設定などが記述された `sw.js` が生成されて、ページ閲覧時にリソースファイルがキャッシュされるようになります。
一度見たことがあるページであれば、オフライン時でも閲覧することが可能になります。

細かいキャッシュの設定は、 `nuxt.config.json` に `pwa.workbox`の項目を追加して、デフォルト設定を上書きしたり追加したりすることができます。

https://pwa.nuxtjs.org/modules/workbox.html#options

```nuxt.config.js
export default {
  ・・・
  pwa: {
    workbox: {
        /* workbox options */
    }
  }
}
```

## ホームスクリーン追加
これは、 `nuxt.config.js` に `manifest`の項目を追加して、そこに設定を追加します。

```nuxt.config.js
export default {
  ・・・
  /*
   ** PWAの設定
   */
  manifest: {
    name: 'Nuxt.jsのPWA',      // アプリの名称
    short_name: 'Nuxt PWA',    // ホーム画面に表示される名称
    display: 'standalone',     // 表示モード  'fullscreen' 'standalone' 'minimal-ui' 'browser'
    theme_color: '#ff4a93',    // アプリケーションの既定のテーマ色を定義
    background_color: '#ffdce6',  // 背景の色
    lang: 'ja',                // 言語
    start_url: '/?mode=pwa',   // アイコンから起動した時のURL
    icons: [
      {
        src: '/icon.png',
        sizes: '512x512',
        type: 'image/png'
      }
    ],
  }
}
```

追加して正しく設定が完了していると、画面下部にインストールを促すバナーが表示され、
追加をタップすると、ホーム画面にアイコンが追加されます。
![w36vm-4e1ak (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/bac71d10-cee8-6bb2-0d49-f50d24c22293.gif)


追加されたアイコンをタップすると、manifestで設定したモードでアプリケーションとしてWEBページを起動できます。
今回はdisplayを `standalone`で設定しているので、アドレスバーなどの表示を消え、テーマカラーに設定した色で画面上部のアイコンや時計のエリアが表示されるようになります。
![0fxif-z76gw (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/66b3d812-0246-9ef5-cc5c-54befa08d9a9.gif)

### デスクトップの場合
PWAとしてホームスクリーンの設定がされている場合、デスクトップPCでもアプリのようにインストールをすることができます。
対応しているサイトの場合は、アドレスバーの横に＋ボタンが表示されるので、それをクリックするとインストールダイアログが表示されます。

<img width="554" alt="スクリーンショット 2019-12-15 13.09.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/cc2f1f19-5512-b0f5-293a-f8f7e4259c47.png">

「インストール」をクリックすると単体のウィンドウで起動することができ、デスクトップアプリのように使用することができます。

<img width="599" alt="スクリーンショット 2019-12-15 13.09.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/a07fefc2-06d4-2504-41ff-a0f63317ea4c.png">

Dockにもアプリのように表示されます。
<img width="390" alt="スクリーンショット 2019-12-15 13.16.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/8df45aed-9965-17ce-4333-dc737a504fd8.png">



## プッシュ通知の対応
次に対応したのはプッシュ通知。
今回は手軽にプッシュ通知を実装したかったので、 [Push7](https://push7.jp/)というサービスを使っています。

導入は以下の手順で行います。

1. 管理画面から `push7-worker.js` と `manifest.json`をダウンロード
2. push7-worker.js を`ルートディレクトリに配置`
3. ダウンロードしたmanifest.jsonの内容を `nuxt.config.js` 内の manifestの項目に追記。
4. 指定されたSDKのタグを貼り付ける。

3.に関しては、以下のようなコードがダウンロードできるので、それを予め設定しているNuxtの設定に追記します。

```nuxt.config.js
export default {
  ・・・
  /*
   ** PWAの設定
   */
  manifest: {
    name: 'Nuxt.jsのPWA',      // アプリの名称
    short_name: 'Nuxt PWA',    // ホーム画面に表示される名称
    display: 'standalone',     // 表示モード  'fullscreen' 'standalone' 'minimal-ui' 'browser'
    theme_color: '#ff4a93',    // アプリケーションの既定のテーマ色を定義
    background_color: '#ffdce6',  // 背景の色
    lang: 'ja',                // 言語
    start_url: '/?mode=pwa',   // アイコンから起動した時のURL
    icons: [
      {
        src: '/icon.png',
        sizes: '512x512',
        type: 'image/png'
      }
    ],
    gcm_sender_id: 'XXXXXXXXXXXX',  // Push7の設定を追記
    gcm_user_visible_only: true     // Push7の設定を追記
  }
}
```

4.に関しては、直接HTMLにタグを貼っても良いのですが、今回はNuxtのプラグインとして作成し、
各ページにそれを読み込ませるかたちで実装をしています。

```javascript:PushNotification.js
class PushNotification {
  constructor(id) {
    this.loadScript().then(() => {
      this.init(id)
    })
  }

  loadScript() {
    return new Promise((resolve) => {
      const doc = document
      const script = doc.createElement('script')
      script.async = false
      script.src = `https://sdk.push7.jp/v2/p7sdk.js`
      doc.body.appendChild(script)
      resolve()
    })
  }
  init(id) {
    const p7 = window.p7
    p7.init(id, {
      mode: 'native',
      subscribe: 'auto'
    }).then(() => {
      console.log('初期化済み')
      // p7.subscribe()
    })
  }
}

export default (ctx, inject) => {
  const $push7 = new PushNotification('プッシュ通知設定のIDを入れる')
  inject('push7', $push7)
}
```

```nuxt.config.js
export default {
  ・・・
  plugins: [{ src: '~plugins/PushNotification.js', ssr: false }],
}
```

サーバーにアップロードが完了したら、Push7の管理画面からプッシュ通知のテスト配信を行います。

<img width="685" alt="スクリーンショット 2019-12-15 12.45.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/22a0140a-ded5-4509-9714-2c94ef560d79.png">

送信ボタンをクリックし、数秒後にはスマホ宛にプッシュ通知が届き、タップすると設定したURLのリンクを開くことができます。

![c3rle-khz7a (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/3a95e05d-1c96-1c11-bcb3-2aa89600eb48.gif)


## 最後に
今回試した施策のうち、PWAによるプッシュ通知はAndroidしか対応していないため、iOSではその恩恵は得られないのですが、
本来ネイティブアプリでしか対応できなかったプッシュ通知がPWAとして実装を行うことで、WEB単体でもプッシュ通知を送ることができるようになりました。
また、デスクトップにも対応したため、WEBアプリをあたかも普通のアプリケーションとして見せるといったことも可能になります。

PWA本当に奥が深い。今度はカメラ周りとかでもっと色々遊んで見ようかと思います。