カレンダーをPWA化してみた（インストール編）


毎年年末に自宅と会社用に卓上カレンダーを購入していたのですが、前々から置く場所も取るし、お金もかかるので「PC上で確認できればなぁ…」という思いがありました。

まっさきに思い浮かんだのが Windows 10 に標準搭載されている「カレンダー」アプリ。
しかし、とっても見づらい…
フリーソフトも探してみましたがいいのが見つからず…
[Google カレンダー](https://calendar.google.com/)は高機能すぎて逆に見づらい…

ないならば、自分で作ろう、カレンダー。

というわけで、カレンダーをPWA（Progressive Web Apps）化し、インストール可能にしてみました。

作成したものは以下より確認できます。

https://taqumo.me/calendar/

## Webページ化

まずはWebページとして見れるようにしましょう！
JavaScript を利用して動的に表示するようにします。

### JavaScript

カレンダーの JavaScript については以下を参考にさせていただきました。
とってもわかりやすい記事ありがとうございます。

https://qiita.com/kan_dai/items/b1850750b883f83b9bee

### 日本の祝日API

日本の祝日については以下 API から取得させていただきました。

https://holidays-jp.github.io/

## PWA（Progressive Web Apps）化してインストール可能にする

ウェブサイトをインストール可能にするには、以下のものが必要になります。

* HTTPS で提供されているウェブサイト
* 正しくフィールドが入力されたウェブマニフェスト
* アイコン
* 登録された Service Worker

### ファイル構成例

必要最低限のファイル構成は以下となります。

```
└─ root
  ├─ index.html
  ├─ service-worker.js
  ├─ manifest.json
  ├─ icon-192.png
  └─ icon-512.png
```

### index.html

* `head` 要素内にある `link` 要素で `manifest.json` ファイルを読み込む
* JavaScript で ServiceWorker である `service-worker.js` ファイルを登録する
* スコープは `navigator.serviceWorker.register()` の第二引数（省略可能）として指定できる

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>インストール可能なウェブサイト</title>
    <link rel="manifest" href="manifest.json">
  </head>

  <body>
    <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker
        .register('service-worker.js', {scope: "/"})
        // 登録成功
        .then((registration) => {
          console.log(
            'ServiceWorker の登録に成功しました。スコープ: ',
            registration.scope,
          )
          registration.onupdatefound = () => {
            registration.update()
          }
        })
        // 登録失敗
        .catch((err) => {
          console.log('ServiceWorker の登録に失敗しました。', err)
        })
    }
    </script>
  </body>
</html>
```

### manifest.json

アプリの名前、説明、アイコンなど、必要な情報を記載します。
詳細は以下を確認してください。

https://developer.mozilla.org/ja/docs/Web/Manifest

ゼロから作成するのは大変なので、以下サイトを利用すると簡単に作成できます。

https://tomitm.github.io/appmanifest/

`manifest.json` の主なキーと説明は以下となります。

* `name` : アプリの正式な名前
* `short_name` : ホーム画面に表示するアプリの省略した名前
* `description` : アプリの説明文
* `lang` : `name` と `short_name` で使用する言語を指定
* `start_url` : アプリの起動時に最初に読み込まれる URL
* `scope` : アプリコンテキストの範囲を定義
* `display` : アプリの表示方法
  * `fullscreen` : 全画面表示
  * `standalone` : ブラウザの UI を非表示
  * `minimal-ui` : 最小限の UI を表示（ブラウザによって UI は異なる）
  * `browser` : ブラウザの UI をそのまま表示
* `orientation` : 画面の縦方向、横方向の向きを定義
  * `any` : すべての向きに対して回転を許可
  * `natural` : `screen.orientation.angle` が 0 (正面) になる向きに固定
  * `landscape` : `landscape-primary`, `landscape-secondary` の省略形
  * `landscape-primary` : 縦長が正面の端末で縦方向に固定
  * `landscape-secondary` : 横長が正面の端末で縦方向に固定
  * `portrait` : `portrait-primary`, `portrait-secondary` の省略形
  * `portrait-primary` : 横長が正面の端末で横方向に固定
  * `portrait-secondary` : 縦長が正面の端末で横方向に固定
* `theme_color` : オペレーティングシステムで使用される UI の基本色
* `icons` : アイコン情報
* `background_color` : アプリの既定の背景色（インストール中およびスプラッシュ画面で利用）

```json:manifest.json
{
  "name": "アプリの正式な名前",
  "short_name": "ホーム画面に表示するアプリの省略した名前",
  "description": "アプリの説明文",
  "lang": "ja",
  "start_url": "index.html",
  "scope": "/",
  "display": "standalone",
  "theme_color": "#fff",
  "icons": [
    {
      "src": "icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "background_color": "#fff"
}
```

### service-worker.js

Service Worker の処理を記述する JavaScript ファイル。
インストール可能にするだけであれば記述は空で大丈夫です。
ただし、 Android で Mini-infobar と呼ばれるインストールを促すバナーを表示させるためには `fetch` イベントを登録する必要があります。

```javascript:service-worker.js
self.addEventListener('fetch', (e) => {
  // ここは空でOK
})
```

### icon.png

`manifest.json` 内で指定するアイコンファイル。

いろいろなサイズのアイコン画像を設定できますが、最低限以下のサイズのアイコン画像が必要なようです。

* 192 x 192
* 512 x 512

## インストールする（Chrome）

PWA化したページを表示すると、アドレスバーにインストールするためのアイコンが表示されます。

![calendar_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/3ab3cd50-b339-b9f0-c7c9-ff32e7ab1a65.png)

クリックするとインストールするか聞いてきます。

![calendar_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/6abe872e-e7ff-1e85-fe3b-176c024e5550.png)

インストールするとデスクトップにショートカットアイコンが作成されます。

![calendar_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/88443d52-f63e-83a4-4330-60259f7a4152.png)

ブックマークバー上の「アプリ」をクリックするか、アドレスバーに `chrome://apps` と入力するとアプリ一覧が表示されます。
アプリが登録されているのが確認できます。

![calendar_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/cc97b778-ee71-99fe-dde7-5bbf6d41217f.png)

デスクトップのアイコンをクリックするとアプリが起動します。

![calendar_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/45f32baf-57fe-b2fa-88b5-93b76dda83ff.png)

アプリの削除はアプリ一覧画面から行うことができます。

![calendar_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/7e68f6ca-daa8-d5d3-4ed2-99dd8dde7e1c.png)