PWAで配ると決めたあとに踏んだ落とし穴 7つ
審査もストアも通さずWebアプリをそのまま配れるのがPWAの利点ですが、更新・キャッシュ・アイコン・インストール判定で実際に事故が起きます。自作アプリで踏んだものを対処つきで書きます。
作ったアプリはPWA(ホーム画面に追加して使うWebアプリ)として配っています。 ストアの審査が要らず、更新も置き換えるだけで済むので、個人開発とは相性が良い選択です。
ただし**「Webアプリがそのままアプリになる」わけではありません**。 実際に配ってから踏んだものを、対処と一緒に並べます。
1. 直したのに直らない(古い版を掴んだままになる)
いちばん深刻です。Service Worker はキャッシュを優先して動くので、 新しい版を置いても、端末によってはしばらく古いコードが動き続けます。
自動更新の設定にしていても、「次に開いたとき」に切り替わるので即座ではありません。 利用者から見ると修正が届いていないのと区別がつきません。
対処は3点セットにしました。
- 動いている版のビルド時刻を画面に表示する(ビルド時に埋め込む)
- 更新履歴を同じ画面に置き、その時刻より後の変更を見比べられるようにする
- 「最新版に更新する」ボタンを置き、押したら Service Worker の登録解除と キャッシュ削除をしてから再読み込みする
3つ目で重要なのは、消してよいものだけを消すことです。 配信物の控え(Cache Storage)は消しますが、 利用者のデータ(IndexedDB)には触りません。ここを一緒に消すと、 不具合を直そうとした人が履歴と設定を失います。
2. HTMLとCSSが別の世代になって、装飾なしの画面が出る
更新直後に、文字とボタンだけの素の画面になる端末がありました。 HTMLは新しい版、CSSは古い版のキャッシュ、という食い違いです。
外部CSSとして読み込んでいる限り、この2つは別々に更新されうるので、 タイミング次第で起こります。ページの見た目が完全に壊れるので影響が大きい割に、 手元では再現しません(開発中はキャッシュが無効なため)。
対処は、CSSをアプリ本体のJSに取り込んで、
起動時に <style> として差し込む形にしました。
本体とスタイルが必ず同じ版で一緒に読み込まれるので、食い違いようがなくなります。
3. ホーム画面のアイコンだけ古いまま残る
アイコンを新しくしても、すでにホーム画面に追加している端末は変わりません。 とくにiOSでは、追加した時点のアイコンが端末側に焼き付きます。
これは技術的に解決できません。一度削除して追加し直してもらう必要があります。
ここに危険があります。 削除と再追加を案内すると、端末内のデータが消える場合があるからです。 データを端末内にだけ置く設計にしていると、これは致命傷になりえます。
そこで案内を出す順番を決めました。
- 先にバックアップを書き出す
- APIキーを控える
- そのうえで削除と再追加
さらに、案内を出す相手を絞りました。 旧アイコンの時代から使っている端末にだけ表示し、 新しく使い始めた端末と、更新を終えた端末には出しません。 全員に出すと、消さなくてよい人まで消してしまいます。
4. 事前キャッシュを盛りすぎて、初回が重くなる
オフラインで動かしたいので、つい何でも事前キャッシュに入れたくなります。 実際には、一部の人しか使わない機能の重いファイルが混ざります。
このアプリではPDF読み取り用のライブラリと文字マップがそれで、 合わせて1MBを大きく超えます。全員が初回に落とす理由がありません。
対処は2段構えです。
- 事前キャッシュからは除外する
- 実際に使ったときに取りに行き、取得できたら30日間キャッシュする
一度でも資料の取り込みを使った端末では次回からオフラインでも動き、 使わない端末は初回が軽いままになります。
なお、除外するにはファイル名が固定されている必要があります。 ビルドの分割設定でチャンク名を明示しておかないと、 名前が毎回変わって除外の指定が効きません。ここは実際に外れていました。
5. インストール済みかどうかの判定が1つでは足りない
「ホーム画面に追加してください」という案内は、 すでに追加している人には出したくありません。
ところが判定方法が環境で分かれます。
| 環境 | 判定 |
|---|---|
| 一般的なブラウザ | 表示モードが standalone かどうかを CSS メディアクエリで見る |
| iOS の Safari | navigator.standalone を見る |
片方だけで判定すると、iOSで追加済みの人に案内が出続けます。 両方を見て、どちらかが真なら追加済みとして扱っています。
6. インストールボタンを出せる環境と出せない環境がある
ブラウザによっては、インストールを促すイベントを受け取って アプリ内のボタンからインストールできます。
iOSにはこのイベントが来ません。 共有ボタンから「ホーム画面に追加」を選んでもらうしかないので、 文章で手順を案内する分岐が必要になります。
「ボタンを出す」だけを実装すると、iOSの利用者には何も起きない画面が残ります。 利用者の多くがiPhoneなら、こちらが本命の導線です。
7. 配信先によってパスの前提が変わる
ルート直下に置くのか、サブディレクトリに置くのかで、 アセットの参照パスが変わります。ホスティング先を移す可能性があるなら、 相対パスを前提にしておくほうが安全です。
マニフェストの start_url と scope も同様です。
ここが実際の配信パスとずれると、
ホーム画面から開いたときにアプリとして扱われず、普通のタブで開くことがあります。
まとめ
PWAで配ると、アプリストアが肩代わりしていたことが全部自分に返ってきます。
| ストアがやっていたこと | PWAでは |
|---|---|
| 版の管理と表示 | 自分で版を画面に出す |
| 更新の完了を保証 | 自分でキャッシュを捨てる手段を用意する |
| アイコンの差し替え | 端末によっては差し替えられない |
| インストール状態の把握 | 環境ごとに判定を分ける |
それでも、審査を待たずに直したものをその日のうちに届けられる利点は大きく、 選択自体は変えていません。 ただし**「Webで動いているから配れる」という認識は間違いでした**。 配るための実装が、思っていたより必要でした。
関連する記事
- AIアプリの更新履歴は「見分けがつくこと」を書く
自動更新されるAIアプリでは、利用者は不具合が直ったのか古い版を掴んでいるのかを区別できません。8日間で38回更新したアプリで、更新履歴の書き方をどう変えたかを書きます。
- 利用者のデータを端末の中だけに置く設計と、そこで諦めたこと
APIキーも履歴も、サーバーへ送らず端末内(IndexedDB)にだけ保存する構成にしました。得られたものと、代わりに諦めることになった機能を書きます。
- 月額ゼロで実用アプリを配る構成と、無料枠の現実的な制約
個人が作ったアプリを、サーバー代もストアの年会費も払わずに配っています。実際に使っている構成と、無料枠ゆえに起きる問題への対処を書きます。
最終更新日: