LoginSignup
1
2

最小PWAのサンプル

Last updated at Posted at 2024-04-27

TL;DR

https://から始まるURLにてhtmlを描画できるURLのheadタグ内で次のタグを記述し、manifest.jsonファイルへのパスを指定すればいけます。
以下はDocumentRoot直下にmanifest.jsonが置いてある場合の例です。
ただし、オフライン時も動作するようにするには別途JavaScriptでサービスワーカーを実装し、静的ファイルのキャッシュ機能をもたせる必要があります。

<link rel="manifest" href="manifest.json">

GitHub でサンプルになるソースコードを公開しています。

上記ソースが実際動作しているのはGitHub Pagesで公開しているこちらをどうぞ。

デスクトップ版FirefoxにPWAをインストールするにはアドオンが必要です。Firefox 86で非対応になった模様です。Android版Firefoxではアドオンなしでもインストールできました。
ちなみにFirefoxはPWAの事をSSB(Site-specific browser、サイト固有のブラウザ)と呼んでいるようです。

雑な説明

PWA(Progressive web apps, プログレッシブウェブアプリ)とは、ざっくり言うとAndroidやiOS、iPadOSやWindows、macOS、Linuxデスクトップなどにアプリのようにインストール・アンインストールでき、独立したウインドウとして利用できるブラウザベースのWebアプリのことです。

PWA側のサービスワーカーによって通信がなくてもキャッシュされたhtmlやJavaScriptだけでもユーザ端末内で起動できます。
また、fetch APIなどで通信することによりクライアントはユーザの端末側、データなどはサーバ側に分割できたり、アップデートの自動配信などにも対応できます。

おまけとしてPWAのインストール元ブラウザにインストールされている機能拡張も有効になるので、Stylustampermonkeyで悪さがし放題です。😎

正確な説明は毎度おなじみMDNを参照ください。

プログレッシブウェブアプリ (PWA) | MDN

実装手順

ここからは実装方法を紹介します。

  1. manifest.jsonの作成
  2. index.htmlからlinkタグでmanifest.jsonファイルをマニフェストファイルとして読み込む
  3. 必要に応じてオフライン動作できるようにするためのサービスワーカー用JavaScriptファイルを作る
  4. インストール機能を実装する。ブラウザの機能でインストールしてもらうなら不要

一般的にはnode.jsのライブラリを使うようですが、私はVanillaJS使いなのでここでは割愛します。

manifest.jsonの概要

jsonにはコメントを入れることができませんので、実際に利用するときはコメント部分をすべて削除してください。

manifest.json
{
    // 正式名。必須。インストール済みアプリリストやタイトルバーに表示される
    "name": "Minimum PWA",

    // OSの一般的なアプリとして振る舞う`fullscreen`や
    // ブラウザのタブとして振る舞う`browser`などがある
    "display": "standalone",

    // WebアプリのID。配布元のドメインを変更したりして
    // URLが変わっても、同一アプリであることを示すことができる
    // アプリ名をそのまま使っても構わない
    "id": "03a25b2d-b372-4e5e-8daa-eb5012b66ac5", 

    // このアプリがアクセスできる範囲の一番外側。
    // これより上のパスにアクセスするときはアプリを離れブラウザで開く
    "scope": "/mini-pwa/",

    // アプリ起動時のURL。ブラウザの実装によって無視されることがある
    "start_url": "/mini-pwa/index.html",
    
    // アプリアイコン。必須。ホーム画面にあるときなど、表示サイズに応じて変更できる
    // ここでは一つだけ指定しているが、サイズやファイルタイプによって複数指定できる
    "icons": [
        {
            // 画像ファイルパス
            "src": "icon256x256.png",

            // ファイルタイプのヒント
            "type": "image/png",

            // 画像サイズ
            "sizes": "256x256"
        }
    ]
}

PWAの実装例

かなりアレな実装ですが、最小のサンプルということで勘弁してください。

ここではPWAのインストールにJavaScriptを使わずブラウザの機能でインストールしてもらう前提にしています。

無題.png ⇐アドレスバーのPWAインストールボタン(Edgeの場合)

また、PWAをインストールさせるページを作るにはhttps://で始まるセキュアなURLが必要です。

トップページ(HTML)

PWAを開いたときの最初のページになるHTMLファイルです。サービスワーカーにキャッシュさせることにより、オフライン起動が可能になります。

index.html
<!DOCTYPE html>
<head>
    <title>Minimum PWA</title>
    <link rel="shortcut icon" type="image/png" href="icon256x256.png"><!-- favicon -->
    <link rel="manifest" href="manifest.json">
</head>
<body>
    <!-- アプリとしての機能 -->
    <button type="button" onclick="alert('UUID: ' + crypto.randomUUID())">Generate</button>

    <script>
        // サービスワーカーの登録。黙って登録しているのでお行儀が悪い
        window.addEventListener("load", (e) => {
            if ("serviceWorker" in navigator) {
                navigator.serviceWorker.register("./sw.js");
            }
        });
    </script>
</body>
</html>

サービスワーカー(JavaScript)

PWAの動的に動作する部分です。

sw.js
const APP_NAME = "mini-pwa";
const VERSION = "202404281828JST"; // 普通に"v1"とかでもよい

// このサービスワーカーのキャッシュデータのキーとなる文字列
// バージョン番号を入れることで、ソースがアップデートされたときに
// キャッシュファイルの更新をする狙い
const CACHE_NAME = APP_NAME + "_" + VERSION;

// 静的ファイルの相対パスを指定し、インストール時にダウンロードしてキャッシュしておくファイル群
// ローカルではルートにアクセスしたときのためにパス"/"を解決してくれないらしいので登録しておく
// jsファイルやcssファイル、画像ファイルなどがあればそれもリストアップしておくと良い
const assets = [
  "/",
  "/index.html",
  "/icon256x256.png",
];

/**
 * サービスワーカーのインストールイベント発生時の処理
 */
self.addEventListener("install", (e) => {
  e.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      // 上記配列で指定したファイル群をダウンロードしてローカルにキャッシュしておく
      // これによりオフラインでも起動できるようになる
      return cache.addAll(assets);
    })
  );
});

/** 
 * サービスワーカーからサーバにアクセスするときの処理
 */
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((response) => {
      // キャッシュされているときは通信せずにローカルのファイルを参照する
      return response ? response : fetch(e.request);
    })
  );
});

/**
 * サービスワーカーが起動するときの処理
 */
self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys().then((keyList) => {
      return Promise.all(
        keyList.map((key) => {
          // このファイル先頭で定義されているファイル名の配列になく、
          // キャッシュされていたらキャッシュ(=ローカル)から削除しておく
          // バージョンアップ時にゴミが残らないようにする工夫
          if (key !== CACHE_NAME) {
            return caches.delete(key);
          }
        })
      );
    })
  );
});

アプリアイコン

icon256x256.png
ダウンロードしたらファイル名を「icon256x256.png」に変更してご利用ください。

動作画面
ZorinOS(Linux)+ Edgeでインストールして実行するとこんな感じ。
image.png

最後に

Microsoft StoreのアプリはPWAが登録でき、Windowsアプリのように振る舞いつつストアの機能で課金の収納代行もしてくれるようです。PWAを公開しているURLが必要なので、公開されているPWAをどう収益化するかは悩みどころですが。ログイン機能でもつけますかね。
これでElectronStripeともおサラバですね!(せやろか

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2