LoginSignup
36
33

More than 1 year has passed since last update.

PWAを超簡単にオフライン表示に対応しよう【PWAの基準変更】

Last updated at Posted at 2021-03-07

こんにちは。突然ですがPWAのオフライン表示対応が必須になります。
対応必須は流石に早すぎるということで撤回し一時見送られたそうです。

ChromeのアップデートによりWebアプリをPWAとしてインストールできるかどうかの基準が見直されます。

Googleからの発表

  • Chrome 89 以降、PWAがオフライン時に有効な応答を返さない場合、開発者ツールのコンソールに警告が表示される。
  • **Chrome 93(今年後半以降リリース予定)**以降、オフラインで適切に動作しないWebアプリはPWAとしてインストールできなくなる。

出典:「Google Chrome 89」が公開 ~ゼロデイ脆弱性1件を含む47件の問題を修正

つまりオフラインでも使えるようにしてね。ってことですね。
現状、オフラインに対応しているPWAサイトはあまりない感じなので早急に対応をすべきでしょうね。
因みにオフライン表示に対応していないと以下の表示が出ます。(もちろん初めてじゃないです)
Screenshot_20210307_144710 (1).jpg

この問題を回避するには至って簡単で、**オフライン用のページを用意するだけでいいんです。**まぁ当たり前ですが。
なので今回はHTML+JSでオフライン対応させる雛形を作ります。

参考:PWAでPUSH通知機能を実装。

実装

注意

PWAはSSL対応が必須です。ご注意ください。(一応localhostでは非SSLでも動きます)

構成

html
├ img
│ └ logo.png
├ index.html
└ sw.js

manifest.json

PWAとして認識させるためにいつものmanifest.jsonを作成します。以下テンプレートです。

manifest.json

{
    "name": "PWA Offline Test",
    "short_name": "PWA",
    "icons": [
        {
            "src": "/img/icon.png",
            "sizes": "144x144",
            "type": "image/png"
        }
    ],
    "start_url": "/",
    "display": "standalone",
    "theme_color": "#99d9ea"
}

Manifest.jsonの詳しい書き方は山ほどあるんで参考にしてください。

ServiceWorker

PWAを動作させるために必要なServiceWorkerを書きます。

sw.js
// バージョン定義
var CACHE_VERSION = 'ca-v1';
var DISP_VERSION = 'ca-d-v1';

// キャッシュの対象にするディレクトリ(css/jsは個別で追加)
var resources = [
  '/',
  '/img'
];

// キャッシュ追加
self.addEventListener('install', function (event) {
  console.log('ServiceWorker Install');
  event.waitUntil(
    caches.open(CACHE_VERSION)
      .then(function (cache) {
        console.log('cache.addAll');
        cache.addAll(resources);
      })
  );
});
// キャッシュ表示
self.addEventListener('fetch', function (event) {
  console.log('ServiceWorker fetch');
  event.respondWith(
    // キャッシュが存在するかチェック
    caches.match(event.request)
      .then(function (response) {
        if (response) {
          return response;
        } else {
          // キャッシュがない場合キャッシュに入れる
          return fetch(event.request)
            .then(function (res) {
              return caches.open(DISP_VERSION)
                .then(function (cache) {
                  console.log('cache.put');
                  cache.put(event.request.url, res.clone());
                  return res;
                });
            })
            .catch(function () {
              // 何もしない
            });
        }
      })
  );
});
// 古いキャッシュを削除
self.addEventListener('activate', function (event) {
  console.log('activate ServiceWorker');
  event.waitUntil(
    caches.keys()
      .then(function (keyList) {
        return Promise.all(keyList.map(function (key) {
          if (key !== CACHE_VERSION && key !== DISP_VERSION) {
            console.log('cache.delete');
            return caches.delete(key);
          }
        }));
      })
  );
  return self.clients.claim();
});

この記事を参考にさせていただきました。

htmlページ

オフラインで表示させるためのHTMLを書きます。その際、さっき書いたやつを読み込ませます。
以下テンプレート

index.html
<head>
    <link rel="manifest" href="/manifest.json">
    <!-- 文字コード設定&モバイル対応化 -->
    <meta charset="utf8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <script>
        // ServiceWorkerを読み込ませる
        window.addEventListener('load', function () {
            if ('serviceWorker' in navigator) {
                navigator.serviceWorker.register('/sw.js')
                    .then(function (registration) {
                        return registration.pushManager.getSubscription().then(function (subscription) {
                            console.log("subscription", subscription)
                            if (subscription) {
                                return subscription
                            }
                            return registration.pushManager.subscribe({
                                userVisibleOnly: true
                            })
                        })
                    }).then(function (subscription) {
                        var endpoint = subscription.endpoint
                        console.log("pushManager endpoint:", endpoint)
                    }).catch(function (error) {
                        console.log("serviceWorker error:", error)
                    })
            }
        })
    </script>
</head>
<body>
    PWAのオフライン表示テスト(フロントページ)
    <br>
    <a href="https://hoge.com/index2.html">2ページ目へ</a>
    <!-- ページの遷移もできます。その際、遷移先ページにもServiceWorkerを読み込ませないとうまく機能しない場合があります -->
    <br>
    <img src="/icon.png">
</body>
</html>

これで実装は終わりです。ためしてみましょう。

動作確認

画面下部にインストールを促すポップアップが表示されるのでインストールしてみます。
Screenshot_20210307_144842 (1).jpg
InkedScreenshot_20210307_144737 (1)_LI.jpg

インストールが終わると通知が表示されますので開いて表示を確認してください。
InkedScreenshot_20210307_144751_LI.jpg

ちゃんと表示ができたら試しに機内モードにします
Screenshot_20210307_144819.jpg

これでアプリを開いても問題なく表示できたらOKです。
Screenshot_20210307_144918.jpg
Screenshot_20210307_144943 (1).jpg

はいちゃんと表示できてますね。ページの遷移も問題ないです。
以上PWAをオフライン化させてみました。基準変更まで短いので早急に対応してくださいねQiitaさん、あなたのことです。
【追記】Qiitaがオフライン表示に対応しました。有難うございます。
Screenshot_20210522_124420.jpg

普段はTwitterブログで色々書いてます。

36
33
2

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
36
33