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のインストール元ブラウザにインストールされている拡張機能も有効になるので、Stylusやtampermonkeyで悪さがし放題です。😎
正確な説明は毎度おなじみMDNを参照ください。
実装手順
ここからは実装方法を紹介します。
-
manifest.json
の作成 -
index.html
からlink
タグでmanifest.json
ファイルをマニフェストファイルとして読み込む - 必要に応じてオフライン動作できるようにするためのサービスワーカー用JavaScriptファイルを作る
- インストール機能を実装する。ブラウザの機能でインストールしてもらうなら不要
一般的にはnode.js
のライブラリを使うようですが、私はVanillaJS
使いなのでここでは割愛します。
manifest.jsonの概要
jsonにはコメントを入れることができませんので、実際に利用するときはコメント部分をすべて削除してください。
{
// 正式名。必須。インストール済みアプリリストやタイトルバーに表示される
"name": "Minimum PWA",
// OSの一般的なアプリとして振る舞う`fullscreen`や
// ブラウザのタブとして振る舞う`browser`などがある
"display": "standalone",
// WebアプリのID。配布元のドメインを変更したりして
// URLが変わっても、同一アプリであることを示すことができる
// アプリ名をそのまま使っても構わない
"id": "03a25b2d-b372-4e5e-8daa-eb5012b66ac5",
// このアプリがアクセスできる範囲の一番外側。
// これより上のパスにアクセスするときはアプリを離れブラウザで開く
"scope": "/",
// アプリ起動時のURL。ブラウザの実装によって無視されることがある
"start_url": "/index.html",
// アプリアイコン。必須。ホーム画面にあるときなど、表示サイズに応じて変更できる
// ここでは一つだけ指定しているが、サイズやファイルタイプによって複数指定できる
"icons": [
{
// 画像ファイルパス
"src": "icon256x256.png",
// ファイルタイプのヒント
"type": "image/png",
// 画像サイズ
"sizes": "256x256"
}
]
}
PWAの実装例
かなりアレな実装ですが、最小のサンプルということで勘弁してください。
ここではPWAのインストールにJavaScriptを使わずブラウザの機能でインストールしてもらう前提にしています。
また、PWAをインストールさせるページを作るにはhttps://
で始まるセキュアなURLが必要です。
トップページ(HTML)
PWAを開いたときの最初のページになる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の動的に動作する部分です。
バージョン番号はちょっとがんはればfetch
APIでmanifest.json
から取ってくることも可能ですが、今回は省略してシンプルに徹しています。
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
」に変更してご利用ください。
動作画面
ZorinOS(Linux)+ Edgeでインストールして実行するとこんな感じ。
最後に
Microsoft StoreのアプリはPWAが登録でき、Windowsアプリのように振る舞いつつストアの機能で課金の収納代行もしてくれるようです。PWAを公開しているURLが必要なので、公開されているPWAをどう収益化するかは悩みどころですが。ログイン機能でもつけますかね。
これでElectron
やStripe
ともおサラバですね!(せやろか