今PWAで意外と出来ること・出来ないこと


こんにちは。[あのちっく](https://twitter.com/anoChick)です。
[commmune Advent Calendar 2023](https://qiita.com/advent-calendar/2023/commmune) 10日目の記事は『PWAで意外と出来ること・出来ないこと』です。
どうぞよろしくお願いします。

https://qiita.com/advent-calendar/2023/commmune


# PWAについて
PWAとは、Webサイトをまるでネイティブアプリのようにホーム画面に追加したり、オフライン利用したり、通知を受け取ることができたりするというコンセプトのことです。
PWAは複数のWeb技術要素によって成り立っています。

詳しいことはweb.devで丁寧に紹介されていますので、そちらを読むと良いかと思います。

https://web.dev/explore/progressive-web-apps?hl=ja

PWAは2015年頃から提唱され、少しずつ仕様の合意とブラウザへの実装が進んできました。

この記事では、最近のPWAの状況を理解するために、現在PWAで出来ること・出来ないことについてざっくり紹介していきます。

# プッシュ通知(Push&Notification)が出来る
サーバサイドから特定のクライアントにメッセージを送信する[Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API)とクライアント端末に通知を表示させる[Notification API](https://developer.mozilla.org/en-US/docs/Web/API/notification)を組み合わせることで、サーバ側からユーザーの端末にプッシュ通知を送ることが出来ます。

今年iOS16.4がリリースされたことにより、Android/iOSの両方で利用可能になりました。


https://developer.apple.com/documentation/usernotifications/sending_web_push_notifications_in_web_apps_and_browsers


# 通知アイコンを自由に指定出来る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/70873842-885a-be3f-e3f8-c8481fd27510.png)
Notification APIの```badge```プロパティに画像URLを指定することで、通知バーに表示されるアイコンなどを自由に変更することが出来ます。

https://developer.mozilla.org/en-US/docs/Web/API/Notification/badge

デフォルトだとブラウザのアイコンが表示されてしまうので、設定することでオリジナルアプリ感を出すことが出来ます。

# 通知にアクション要求を組み込むことが出来る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/472380fe-2581-713b-f3e3-db8eef43a0e7.png)
Notification APIの```actions ```プロパティを設定することでボタンやテキスト入力など、ユーザーからのアクションを要求することが出来ます。
送信すると、入力された情報は```notificationclick```イベントで受け取ることが出来ます。
```javascript
self.addEventListener("notificationclick", (event) => {
  const reply = event.reply;
  ...
});
```

https://web.dev/articles/push-notifications-notification-behaviour?hl=ja


# ホーム画面上のアイコンを大きく見せることが出来る
通常、Webサイトを「ホーム画面に追加」あるいは「インストール」を行うと、下の画像のように余白が生まれてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/f8f0bb64-da7d-3ebf-4ca1-db48fb247eaa.png)

ですが、これは```manifest.json```の```icon.purpose```プロパティに```maskable```を追加すると、アイコン画像がフル表示されるようになります。

```manifest.json
{
  "icons": [
    {
      "purpose": "any maskable",
      "src": "https://pg.anochick.com/icon.png",
      "sizes": "192x192 512x512",
      "type": "image/png"
    }
  ]
}
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/ebc9c75c-4958-71da-bd15-1359e1788232.png)

https://web.dev/articles/maskable-icon?hl=ja


# バッジの表示ができる
PWAとしてホーム画面に追加したアプリアイコンは```navigator.setAppBadge```と```navigator.clearAppBadge```バッジ数を表示・クリア出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/27d15740-2598-5401-3e52-9ac913143abc.png)

https://webkit.org/blog/14112/badging-for-home-screen-web-apps/



# インストールボタンを画面上に配置することが出来る
通常PWAをインストールする場合、ブラウザのページメニューから[ホーム画面に追加]あるいは[インストール]を選択することでPWAとしてのインストールが出来るわけですが、ちょっと分かりづらいのが難点です。

しかし、ユーザーがページ上の任意のボタンをクリックしたときにインストール確認プロンプトを表示させるような事もできます。

以下は、Reactでのインストールボタンの実装例です。

```jsx
import { useEffect, useRef, useState } from "react";

export const PWAInstallationButton = () => {
  const deferredPromptRef = useRef(null);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    const beforeInstallPromptHandler = () => {
      setReady(true);
      deferredPromptRef.current = event;
    };

    window.addEventListener("beforeinstallprompt", beforeInstallPromptHandler);
    return () => {
      window.removeEventListener(
        "beforeinstallprompt",
        beforeInstallPromptHandler
      );
    };
  }, []);

  const handleClickInstall = async () => {
    const deferredPrompt = deferredPromptRef.current;
    if (deferredPrompt) {
      // インストールプロンプトを表示する
      deferredPrompt.prompt();
    }
  };

  return (
    <button disabled={!ready} onClick={handleClickInstall}>
      Install
    </button>
  );
};

```
ちなみに```beforeinstallprompt```のイベントハンドラはインストール済みのときには実行されないので、この仕組みを使って「インストール済みかどうか」を判断することも出来ます。




https://developer.mozilla.org/en-US/docs/Web/API/BeforeInstallPromptEvent

# インストール時のアプリ情報を設定できる
manifest.jsonでdescriptionやscreenshotsを指定することで、PWAをインストールする前の確認画面でいい感じのアプリ紹介が表示されるようになります。

```manifest.json
{
  "description": "あのちっくが実験的なことをする場所です。",
  "screenshots": [
    {
      "src": "https://pg.anochick.com/ss1.png",
      "size": "715x988",
      "type": "image/png"
    },
    {
      "src": "https://pg.anochick.com/ss2.png",
      "size": "715x988",
      "type": "image/png"
    }
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/1bc2e75a-ed6e-b00f-853b-db415ff3b155.png)


# アプリショートカットを作ることが出来る
Androidのアプリアイコンを長押ししたときに表示されるアプリショートカットも```manifest.json```で設定することが出来ます。

```manifest.json
{
  "shortcuts": [
    {
      "name": "favicon clock",
      "url": "/ac/2023/commmune/3",
      "icons": [
        {
          "src": "clockicon.png",
          "type": "image/png",
          "sizes": "192x192"
        }
      ]
    }
  ]
}
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22392/554ea73f-a62d-bbae-d208-5b473160042e.png)



# iOSでは使えない機能が多数ある

と、ここまで紹介して「へー、いまPWAって結構ネイティブアプリっぽく振る舞えるんだなー」と思った方は多いと思います。
ですが、今回紹介した殆どの機能は残念ながら現在はiOSでは利用できません。具体的には以下の機能がiOSで利用できない状況です。

- 通知にアクション要求を組み込む
- インストールボタンを画面上に配置する
- インストール時のアプリ情報表示
- アプリショートカット

とはいえ、今年iOSでプッシュ通知が出来るようになったことは本当に大きな前進だと考えており、今後iOS側のPWA関連機能はどんどん増えていくのではないかと期待しています。

# おわり

以上です。ありがとうございました。