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分以上の間隔がある
- ブラウザがシークレットモードではない