Web Notifications で通知する

# はじめに
Web Notifications は、ブラウザで通知機能を行うための仕様です。
今回はこれを試してみました。

# Webサーバ（nginx）
何はともあれ、Webサーバが必要ですのでインストールします。
MacBook には最初から Apache が入っていますが、これは使いたくないので別にインストールします。
私の MacBook には Docker for Mac がインストールしてあるので簡単に作れます。

以下のコマンドで nginx のコンテナを作成します。

```bash
$ docker run -d -p 80:80 --name webserver nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
6d827a3ef358: Pull complete 
b556b18c7952: Pull complete 
03558b976e24: Pull complete 
9abee7e1ef9d: Pull complete 
Digest: sha256:52f84ace6ea43f2f58937e5f9fc562e99ad6876e82b99d171916c1ece587c188
Status: Downloaded newer image for nginx:latest
e2fdc7b02c011813ae1f64e6b0ac7d6904908543e5210d4962a51ebb8772b34f
$
```
アクセスして **Welcome画面** が表示されれば OK です。

![ngix](https://qiita-image-store.s3.amazonaws.com/0/134613/6f05d2cf-1385-4b87-554c-3b34fcaf628d.png)

ただ、このままではファイルをデプロイするのが面倒なので、
docker の Volume 機能を使用してホスト上のディレクトリを
nginx の Document Root にマウントします。

* 一度、コンテナを停止してから削除します。

```bash
$ docker stop webserver
webserver
$ docker rm webserver
webserver
$ 
```

* Volume を指定して再度コンテナを起動します。(カレントを Document Root に指定)

```bash
$ docker run -d -p 80:80 -v $PWD:/usr/share/nginx/html --name webserver nginx
78d4d793320f5659bd1b038a067e865a913a04f015a7bd30fd9cdce2c2f53157
$
```

* カレントに適当な index.html を作成してブラウザで確認します。

![hello](https://qiita-image-store.s3.amazonaws.com/0/134613/a386d89c-6f5b-9cc2-3aed-951a1820a9d1.png)

次回からは以下のコマンドで起動／停止します。

```bash
$ docker start webserver
webserver
$ docker stop webserver
webserver
$
```

# 通知 - Notifications API
通知は Notifications API という Javascript API を使います。

Notifications API で通知を表示するためには、最初にユーザに許可を得る必要があります。
許可しないともちろん通知は表示されません。

## 通知の表示許可
![通知](https://qiita-image-store.s3.amazonaws.com/0/134613/a327ff15-4999-3df3-8b61-e70b0f52fd75.png)

Notification.requestPermission() を呼び出すと、上記のようなダイアログが表示されます。
既に許可／拒否している場合はダイアログは表示されずに、直ぐにコールバックが呼び出されたので、現在の状態を気にせずに呼び出しても平気です。

```js:javascript
  // ブラウザが通知をサポートしているか確認する
  if (!('Notification' in window)) {
    alert('未対応のブラウザです');
  }
  else {
    // 許可を求める
    Notification.requestPermission()
      .then((permission) => {
        if (permission == 'granted') {
          // 許可
        } else if (permission == 'denied') {
          // 拒否
        } else if (permission == 'default') {
          // 無視
        }
      });
  }
```

一度、許可や拒否をした後は、ブラウザで設定を元（デフォルトに設定）に戻さないと再度ダイアログを表示することができません。
Chrome の場合はアドレスバー左の赤丸をクリックすると通知設定を変更できました。

## 通知の表示
通知には様々な内容を含めることができます。
以下に一部を記載します。

| 項目       |    説明                                        |
|:----------|:-----------------------------------------------|
| title     | 通知ウィンドウの上部に表示される。                      |
| body      | 通知の本文でタイトルの下に表示される。                  |
| icon      | 通知に表示されるアイコンのURL。                       |
| tag       | 通知の識別タグ。同じタグを指定すると通知が置き換えられる。  |
| data      | 通知に関連付ける任意のデータ。                       |

title 以外はオプションです。

通知の表示は簡単で、タイトルとオプションを指定して Notification インスタンスを生成するだけです。

```js:javascript
    var n = new Notification(
      title,
      {
        body: '本文です',
        icon: 'img/xxx.png',
        tag: '',
        data: {
          xxx: '任意のデータ'
        }
      }
    );
```

色々なブラウザで表示してみましたが、チョットずつ違うんですね。
改行できなかったり、アイコンが表示されなかったり。 (^^;

■ Chrome
![通知 Chrome](https://qiita-image-store.s3.amazonaws.com/0/134613/9ff1756a-7984-eedc-bff1-d330d26b87ea.png)

■ Firefox
![通知 Firefox](https://qiita-image-store.s3.amazonaws.com/0/134613/8bffea5a-05cf-ffad-0595-771b8eb0f080.png)

■ Safari
![通知 Safari](https://qiita-image-store.s3.amazonaws.com/0/134613/3e96fdc1-6e7f-2512-f958-6880be020e87.png)

■ Edge
![notification_edge.png](https://qiita-image-store.s3.amazonaws.com/0/134613/b95c12ab-8463-7fe6-1157-e217fd1baf97.png)

■ Vivaldi
![通知 Vivaldi](https://qiita-image-store.s3.amazonaws.com/0/134613/2934e2b0-e3d6-7c5e-de92-c2cafa5cc2d6.png)

## tag の指定
| ブラウザ | tagなし | tagあり |
|---------|:-----------|:-----------|
| Chrome  | 最大３つまで表示し、１つ閉じたら次の通知が表示された。<br>![通知 tag](https://qiita-image-store.s3.amazonaws.com/0/134613/ccb78e3b-0949-e53b-d2b5-2599deabeece.png) | 同じ tag を指定すれば、ちゃんと通知が置き換わった。 |
| Firefox | 通知したらどんどん表示される。<br>Mac では重なって表示されたので、１つしか表示してないように見えた。<br>Windows ではちゃんと表示された。 | 同じ tag を指定すれば、ちゃんと通知が置き換わった。 |
| Safari  | 通知したらどんどん表示される。<br>Mac では重なって表示されたので、１つしか表示してないように見えた。 | 同じ tag を指定すれば、ちゃんと通知が置き換わった。 |
| Edge    | 1つ閉じたら次の通知が表示された。 | tag なしと同じ動作をした。 |
| Vivaldi | 通知したらどんどん表示される。<br>Mac では重なって表示されたので、１つしか表示してないように見えた。<br>Windows ではちゃんと表示された。 | tag を指定すると２回目から表示されない。 |

## 通知を閉じる
表示された通知は少し (4 秒程度) 経過したら自動的に閉じますが、動作が異なるブラウザがあったのでまとめました。

| ブラウザ  | 自動的に<br>閉じるまでの秒数 |
|---------|:-----------:|
| Chrome  | 20秒        |
| Firefox | 4秒         |
| Safari  | 4秒         |
| Edge    | 6秒         |
| Vivaldi | 4秒<br>Windows版は20秒 |

以下のサイトにいい情報が載っていました。
https://developer.mozilla.org/ja/docs/WebAPI/Using_Web_Notifications
> Firefox および Safari は、少し (4 秒程度) 経過したら自動的に通知を閉じます。またこれは、オペレーティングシステムレベルで行われます。一方 Chrome など、動作が異なるブラウザがあります。すべてのブラウザで確実に通知を閉じるには 4 秒後に通知を閉じるため、前出の関数の末尾に Notification.close 関数を収めた setTimeout() 関数を置きます。close() を通知に関連付けて呼び出すために bind() を使用していることに注意してください。

**通知の表示** で書いたコードに４秒程度経過後に自動的に閉じる処理を追加します。

```js:javascript
    var n = new Notification(
      title,
      {
        body: '本文です',
        icon: 'img/xxx.png',
        tag: '',
        data: {
          xxx: '任意のデータ'
        }
      }
    );
    // 確実に通知を閉じる
    setTimeout(n.close.bind(n), 5000);
```

# まとめ
かなり簡単に実装できるので、機会があったら使ってみようと思いました。
ただ、使いすぎには注意が必要だと。