Webページがアプリのようにインストールできてオフラインでも動作するPWAを作る
PWA(Progressive Web Apps)とはWebページがアプリのようにインストールできてオフラインでも動作する機能です。
Androidはかなり対応している機能が多いですが、iPhone(iOS)は対応している機能が少ないです。
これから説明するファイルは全て
/javascript/pwa/
ディレクトリに配置するものとして説明します。
| /javascript/pwa/index.html | メインファイル |
| /javascript/pwa/manifest.json | マニフェスト |
| /javascript/pwa/service-worker.js | サービスワーカー |
| /javascript/pwa/icon.png | アイコン(192x192) |
index.htmlファイル
navigator.serviceWorker.register('./service-worker.js',
でサービスワーカー(バックグラウンド処理を担当する特別なJavaScript)のスクリプトファイルを指定しています。
{scope: '/javascript/pwa/'}
でスコープを指定しています。
つまり、どのパス以下の通信やデータのやり取りを途中で横取りするできるかを決定します。
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>何らかのタイトル</title>
<meta name="Description" content="説明">
<META name="Keywords" content="キーワード">
<!-- マニフェストファイルを指定する -->
<link rel="manifest" href="manifest.json">
<!-- アドレスバー等のブラウザのUIを非表示 -->
<meta name="mobile-web-app-capable" content="yes">
<!-- default(Safariと同じ) black(黒) black-translucent(ステータスバーをコンテンツに含める) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- ホーム画面に表示されるアプリ名 -->
<meta name="apple-mobile-web-app-title" content="アプリ名">
<!-- ホーム画面に表示されるアプリアイコン -->
<link rel="apple-touch-icon" href="icon.png">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<script>
//サービスワーカーの登録
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'./service-worker.js',
//スコープを省略すると service-worker.js のディレクトリ以下となる
{scope: '/javascript/pwa/'}
).then(function(reg){
console.log('ServiceWorkerの登録成功 スコープ: ', reg.scope);
}).catch(function(err){
console.log('ServiceWorkerの登録失敗: ', err);
});
}
</script>
</head>
<body>
PWAアプリのコンテンツ
</body>
</html>
manifest.json ファイルについて
- short_name の設定は必須(スマホのデスクトップ上にアイコンと共に表示される文字)
-
display は Webアプリをどのように扱うかを指定するもので
fullscreen, standalone, minimal-ui, browser のいずれかを指定する - start_urlはホーム画面を追加する際、どのURLを表示して起動するか
- 192x192 のサイズのアイコン設定が必須
{
"lang":"ja",
"name" : "アプリケーションの名前",
"short_name" : "短縮アプリ名",
"display" : "standalone",
"start_url" : "https://mam-mam.net/javascript/pwa/index.html",
"background_color": "#FFFFFF",
"theme_color" : "#FFFFFF",
"icons": [
{
"src" : "icon.png",
"sizes": "192x192",
"type" : "image/png"
},
]
}
service-worker.js ファイル
CACHE_NAME は キャッシュの名前を入れます。アプリケーションがバージョンアップ時(index.html等が更新された場合)には
var CACHE_NAME='v1.1-pwa-cache-name';
のように名前を変えなければキャッシュが永遠に更新されません。
urlsToCache にキャッシュするファイルを service-worker.js を基準とする相対パスで指定します。
また、service-worker.js より上位ディレクトリを指定してもキャッシュできません。
//キャッシュの名前 var CACHE_NAME='v1.0-pwa-cache-name'; //キャッシュ対象URL一覧配列 var urlsToCache = [ '/javascript/pwa/', '/javascript/pwa/index.html', '/javascript/pwa/icon.png', ]; //インストール処理(キャッシュに入れる) self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME).then(function(cache) { return cache.addAll(urlsToCache.map(url => new Request(url, {credentials: 'same-origin'}))); }) ); }); //リソースフェッチ時のキャッシュロード処理 self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request).then(function(response){ return response || fetch(event.request); }) ); }); // アクティベーションイベント:不要なキャッシュを削除 self.addEventListener('activate', event => { console.log("activated"); const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (!cacheWhitelist.includes(cacheName)) { //console.log('Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }) ); });
実際のサンプル
インストール要件は以下のようです。
-
次の情報が記述されたmanifest.jsonファイルが存在
- name(バナーで使用)
- short_name(ホーム画面で使用)
- 192x192 の png アイコン(image/png の指定が必要)
- start_url
- サイトに Service Worker が登録されている
- HTTPS である(Service Worker を使用するために必要)
- 2回以上のアクセスで5分以上の間隔がある
- ブラウザがシークレットモードではない
