PWA

Service Worker やマニフェストを活用し、Web 技術でオフライン対応やプッシュ通知などネイティブアプリに近い体験を提供するアプローチ

Webモバイル
PWA」の技術書を見る →

PWA とは

PWA (Progressive Web App) は、Service Worker、Web App Manifest、HTTPS を組み合わせて、Web アプリケーションにネイティブアプリに近い体験を提供するアプローチである。この呼び名は 2015 年 6 月、当時 Google Chrome のエンジニアだった Alex Russell とデザイナーの Frances Berriman が付けたもので、単一企業が出した規格ではなく、ブラウザに揃いはじめていた機能を束ねる呼称として提案された。オフライン対応、プッシュ通知、ホーム画面へのインストールなどを Web 技術だけで実現する。

アプリストアを経由せずにユーザーに配布でき、URL でシェアできる。更新もサーバー側のデプロイだけで完了し、ユーザーに更新操作を求めずに済む。ただしこの手軽さは Service Worker のキャッシュ設計に依存する。設計を誤ると、新しい版を配ったのに端末では古い画面が出続ける (後述)。

PWA の 3 つの柱

PWA の 3 つの柱を以下にまとめる。

技術役割具体的な機能
Service Workerバックグラウンド処理オフラインキャッシュ、プッシュ通知、バックグラウンド同期
Web App Manifestアプリのメタデータホーム画面アイコン、スプラッシュスクリーン、表示モード
HTTPSセキュアな通信Service Worker の動作要件 (localhost は例外)

Service Worker が動くのは安全なコンテキストに限られるが、ローカル開発のために http://localhost は例外として扱われる。なお、インストール可能かどうかを決めるのは Manifest と安全なコンテキストで、Service Worker の登録はインストールの必須要件ではない。Chromium 系ブラウザがインストールを提示する条件は Manifest に name (または short_name)、192px と 512px のアイコン、start_urldisplay が揃っていることで、ここに Service Worker は入らない (2026 年 8 月時点)。それでもオフライン体験を出すには Service Worker が要るため、実務では 3 つを一組で用意する。

Service Worker によるオフライン対応

Service Worker はブラウザとネットワークの間に位置するプロキシで、リクエストをインターセプトしてキャッシュから応答できる。

// service-worker.ts
const sw = self as unknown as ServiceWorkerGlobalScope;

sw.addEventListener('fetch', (event: FetchEvent) => {
  // Cache API に保存できるのは GET のみ。POST などは素通しする
  if (event.request.method !== 'GET') return;
  event.respondWith(
    caches.match(event.request).then(cached => {
      if (cached) return cached; // キャッシュがあればそこから返す (オフライン対応)
      return fetch(event.request).then(response => {
        const clone = response.clone();
        // waitUntil に載せないと、保存が終わる前に Service Worker が停止し得る
        event.waitUntil(caches.open('v1').then(cache => cache.put(event.request, clone)));
        return response;
      });
    })
  );
});

この例はキャッシュ優先で、オフライン強度は高い代わりに、いったんキャッシュに載った HTML はサーバーを更新しても古いまま返る。HTML やデータ取得はネットワーク優先にして、失敗したときだけキャッシュへ落とすほうが安全だ。あわせてキャッシュ名 (v1) をリリースごとに変え、activate イベントで古いキャッシュを削除しておかないと、端末側に旧版が積み残る。

Web App Manifest

Web App Manifest の例を示す。

{
  "name": "IT 技書の森",
  "short_name": "技書の森",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#2d5016",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

display: "standalone" を設定すると、ブラウザの UI (アドレスバー、タブ) が非表示になり、ネイティブアプリのような見た目になる。

ネイティブアプリとの比較

ネイティブアプリとの主な違いを以下に比較する。

観点PWAネイティブアプリ
配布URL でアクセス、ストア不要App Store / Google Play
更新サーバー側デプロイのみストア審査 + ユーザーの更新
オフラインService Worker でキャッシュネイティブにサポート
プッシュ通知Web Push API (iOS はホーム画面追加が前提)フルサポート
デバイス API制限あり (Bluetooth, NFC は一部)フルアクセス
パフォーマンスブラウザエンジンに依存ネイティブコードで高速

iOS のプッシュ通知は 2023 年 2 月の iOS / iPadOS 16.4 で扱いが変わり、ホーム画面に追加した Web アプリからは Push API と Notification API が使えるようになった。裏を返すと Safari のタブで開いたままでは通知を出せないため、通知を前提にする設計ではホーム画面への追加を促す導線が欠かせない (2026 年 8 月時点)。

PWA が適するケース

  • コンテンツ中心のアプリ (ニュース、ブログ、EC)
  • オフラインでも閲覧したいアプリ (ドキュメント、レシピ)
  • アプリストアの審査を避けたい場合
  • Web とモバイルで同一コードベースを使いたい場合

PWA が不向きなケース

  • 高度なデバイス API が必要 (AR、高精度 GPS)
  • ゲームなど高いグラフィックス性能が必要
  • Safari のタブで開いたまま iOS へプッシュ通知を送りたい場合 (iOS 16.4 以降でもホーム画面に追加した Web アプリ限定)

CloudFront + S3 での PWA ホスティング

静的サイトとして S3 にデプロイし、CloudFront で配信する構成は PWA と相性が良い。Service Worker のキャッシュと CloudFront のキャッシュを組み合わせることで、高速な配信とオフライン対応を両立できる。

Service Worker のファイル (sw.js) には Cache-Control: no-cache を設定し、他の静的アセットは長期キャッシュにする。ブラウザは更新チェックのとき Service Worker のメインスクリプトを常にネットワークから取り直す (updateViaCache の既定値 imports の挙動) ので、no-cache が実際に効くのは CloudFront のエッジキャッシュ対策としてだ。エッジに古い sw.js が残ると新しいキャッシュ定義が端末へ届かず、更新が止まったように見える。

体系的に学ぶなら関連書籍を参照してほしい。

この記事は役に立ちましたか?

関連用語

関連する記事