iOSのPWA対応時に気をつけるべきこと

iOS（Safari）は、Androidに比べるとHTML標準仕様への対応が遅れがちです。
PWA仕様への対応も例に漏れず、最新のiOS15.2においても不完全な状態です。

それでもiOS13辺りからはそれなりに使える状態になってきたので、個人的に開発しているWebアプリではiOS13.4以降をPWAに対応させました。

今回はその経験から、iOSのPWA対応時に気をつけるべき事やちょっとしたテクニックを紹介します。

## PWA対応の目的

なぜWebアプリをPWA対応させるのか？

自分としては以下2点がPWA対応の主なモチベーションだと考えています。

 - ネイティブアプリのようにスマートフォンのホーム画面に導線を置ける
 - アドレスバーなど不要なUI無しのフルスクリーンでWebアプリを起動できる

実はこの2点に関しては、Webアプリモードという機能を使うことでiOS4の頃には既に実現可能でした。

ただWebアプリモードはOAuthが使えなかったり起動時のURLを指定できなかったりブラウザバックできなかったりで使いづらい点も多く、PWAとして良い感じに生まれ変わることを期待していました。

## iOSの歩み
iOS側のPWA対応は以下のようにじわじわ進んできました
（O=よくなった点 X=問題点）

### iOS11.3 : Webアプリマニフェストを読めるようになっただけのWebアプリモード期
 - O Webアプリマニフェストの読み込みに対応
 - X 別ドメインへの遷移はSafariに切り替わってしまう（OAuthなどが使えない）
 - X ブラウザバックできない
 - X 非アクティブになるたびにstart_urlに戻される

### iOS12.2 : 良い感じになりかけたけど予想外のバグが混入期
 - O 別ドメインへの遷移はSFSafariViewControllerのような挙動になりOAuthも可能になった
 - O 画面端からのスワイプで戻る/進むができるようになった
 - O 非アクティブでstart_urlに戻される問題が解消
 - X 逆にタスク切ってもstart_urlでなく前回表示時の最終URLが開かれる問題が発生


### iOS13.0 : 要件次第では使っても良さそう期
 - O start_urlまわりの問題が解消
 - X カメラの起動が出来ない等のイレギュラーな問題が残る

### iOS13.4 : それなりに使える期
 - O カメラの起動もできるようになった
 - ? Webアプリモードの挙動がPWAとほぼ同じに変更された（このバージョンをPWA対応の一旦の着地点として共通化したのかなと考えています）

### iOS15.2 : 現在
iOS13.4から大きな変化はなく、Androidと比べると色々機能が足りないものの、それなりに使える状態にはなっています。

ちなみにAppleの発表によると、2021年6月3日時点でiOS/iPadOSユーザーの約8割はiOS14/iPadOS14に移行しているようで、iOS15がリリースされている現在はさらに多くのユーザーがPWAの恩恵を受けられ状態になっているはずです。
<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142643/f21b70fd-598f-395e-129e-9dc9095cc19c.png"> <img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142643/6061e0a3-afa9-7fe9-f184-66569e0ee972.png">
https://developer.apple.com/support/app-store/

ということでここからは本題の、iOSのPWA対応時の注意点を紹介します。

## 注意点① PWAだと動かなくなる機能がある
Safariだと問題ないのにPWAだと動かない！！という事があったりします。
iOSの歩みに書いた通り、iOS13.4まではPWAだとカメラが起動できない状態でした。
他の問題が現在も残っている可能性はあるので、既存のWebアプリをPWA対応させる際は要注意です。

ちなみに、個人開発のWebアプリではカメラの利用が必須要件だったので、「ホーム画面に追加」した場合にiOS13.3まではSafariのブックマーク、iOS13.4からはPWAとして動くようにするため、以下のような実装をしました。

```js
if ({Safariのバージョンが13.1以上の場合}) {
    const manifestLink = document.createElement('link');
    manifestLink.rel = 'manifest';
    manifestLink.href = {Webアプリマニフェストファイルのパス};
    document.getElementsByTagName('head')[0].appendChild(manifestLink);
}
```

iOSではユーザーが「ホーム画面に追加」を押す前にWebアプリマニフェストを差し込めばPWAとしてホームに追加させる事ができるので、バージョン判定をした上で動的にWebアプリマニフェストの差し込みを行っています。

iOSバージョンでなくSafariのバージョンを見ている理由は、iPadでもPWA対応したかった為です。
iPadOSのuseragentはmacOSに偽装されているためiOSバージョンでは判定できませんが、Safariは同じものが使用されます。
そのため、iOS13.4相当のSafariバージョン13.1を判定条件に使えばどちらもカバーできる訳です。

また、iOSのPWAとSafariはCookieを共有していません。
Cookieの利用を前提として「ブラウザ → ネイティブアプリ → ブラウザ」というような遷移があるWebアプリでは、PWA対応によって「PWA → ネイティブアプリ → Safari」という遷移に変わる事で問題が出る可能性があります。
外部の認証システムなどを採用している場合はご注意ください。（LINEさん、LINEログイン動かないですよ！）

## 注意点② iOSのWebアプリマニフェスト対応状況

Androidと同じ調子でWebアプリマニフェストを設定しても動作しない機能がいくつかあります

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

例えばホーム画面追加時のアイコンはどのWebアプリでも用意すると思いますが、iOSはWebアプリマニフェストの`icons`の設定を無視します。
ではどうするかというと、従来の「ホーム画面に追加」の仕様に則って以下のようにHTMLのlinkタグとして設定します。

```html
<link rel="apple-touch-icon" href="./icon_ios.png">
```

アイコン絡みでもう一点、**iOSはアイコンの角丸加工をOS側で勝手に行うので、アイコン画像は縁加工無しの正方形で用意**してください。

## 注意点③ リロード手段を考える

AndroidはPWAでもPull To Refresh（上から下にスワイプでページ更新）ができますが、iOSのPWAにはOS提供のページ更新操作はないので、リロード手段が必要なら自前での実装になります。
（最近のiOS SafariにはPull To Refreshが実装されているので、いずれPWAにも反映されることを期待しています）

## 注意点④ ホームバーとの干渉を考える
iPhoneXからのホームボタンの無いiOS端末では、画面下部にホームバーが表示されるようになりました。

Safariを使う分には下部にあるSafariUIよりも下にホームバーが出るので不都合はなかったりしますが、SafariUIを消したPWAだとWebアプリのUIと干渉する可能性があります。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142643/db44c356-a8d4-7030-c567-4e2a8d8f57e8.png">

ホームバーの領域はCSSの`env(safe-area-inset-bottom)`で取得できるので、例えば以下のようなCSSでホームバー領域を避ける事ができます。

```css
body {
  padding-bottom: env(safe-area-inset-bottom);
}
```

JavaScriptでセーフエリアを取得したい場合は、上記CSSの結果を次のようなコードで取得する事ができます。

```javascript
const safeArea = parseInt(getComputedStyle(document.body).getPropertyValue("padding-bottom"));
```

ここで1つ注意として、PWA起動直後に上記コードを実行しても正しいセーフエリアは取得できません（Safariなら取れるんですが...）
起動してから40msくらい経過すれば正しい値が取れることを確認したので、実装時はその辺の工夫が必要になります。

## 注意点⑤ URLのシェア方法を考える
PWAといえどもWebアプリ、Webアプリの利点といえるURLでの気軽な共有は捨てがたい。

AndroidのPWAなら通知領域で起動中のページのURLをコピーできますが、iOSのPWAにはそのような機能はありません。

Web Share APIの使い所かもしれません。

https://developer.mozilla.org/ja/docs/Web/API/Navigator/share

## 最後に
ここまでiOS PWA対応の注意点を書いてきました。
色々厄介ごとはあるものの、多くのiOSユーザーがPWAの恩恵を受けられる環境が整ってきています。
PWA対応したWebアプリをどんどん増やし、Appleさんに圧をかけていきましょう（Push API使わせてください!!）

PWAの最小実装や動作確認のリポジトリをGitHubで公開しているので、興味があれば覗いてみてください。

https://github.com/zprodev/pwa-test