PWA(Progressive Web Apps)とは、Webサイトにネイティブアプリのような機能を持たせたものです。ブラウザからインストールできて、オフラインでも動作させること可能になります。また、特別なツールは必要なく、HTMLとJavaScriptで作成できます。今回は、PWAとはどのような仕組みで構成されるのか確認してみましょう。

  • 今回作成するPWAのサンプル - ファイルを4つ用意すると作れる

    今回作成するPWAのサンプル - ファイルを4つ用意すると作れる

PWAの機能について

WebサイトがPWAに対応するとどんな良いことがあるのでしょうか。まず、ネイティブアプリのように、インストールできるというのが大きなメリットです。スマートフォンであれば「ホーム画面」にアプリを配置できます。PCでもアプリケーションフォルダにショートカットが作成されるので、起動が容易になります。例えば、以下はChromeでTwitterを開いてインストールしたところです。ネイティブアプリのようにアイコンから起動できて、アドレスバーもなくすぐにアプリが実行できるのがメリットです。

  • Twitterをインストールして起動したところ

    Twitterをインストールして起動したところ

そして、Service Workerの仕組みを利用することで、コンテンツをローカルにキャッシュして、ユーザーがオフラインの状態でも、サイトを利用することができるようになります。

特にスマートフォンでは、移動時など一時的に通信状態が悪くなり、オフラインになってしまうこともよくあります。業務ツールなどがWebアプリとして提供されていた場合、開いて使おうとしたら通信状態が悪くて情報が見られない、計算ツールが使えなかったというのは、とても不便です。PWAに対応しておけば、こうした問題がなくなります。

また、Webプッシュ通知を利用できます。OSの通知機能を利用して、サイトの更新情報を通知できます。このように、PWA化することで、たくさんのメリットを享受できるようになります。

PWA化のために必要な作業

まず、Webサイトをインストール可能にするための作業を確認してみましょう。最低限必要なのは次の四点です。

  • (1) Webアプリのアイコンを用意する
  • (2) マニフェストファイルを用意する
  • (3) Service Worker APIに対応する
  • (4) HTTPS対応のサイトに配置する

(1)アイコンを用意しよう

一つずつ確認していきましょう。まず、最初の(1)ですが、インストールできるアプリにするためには、アプリのアイコンを用意する必要があります。アイコンは、異なるサイズのPNG画像ファイルを用意します。どのサイズのものを用意するかは、主にどの端末に対応したいかによって異なります。大は小を兼ねるという点から、512x512ピクセルなどサイズの大きな画像、あるいは、SVG形式の画像を作成して、それを元にジェネレーターなどでアイコンを自動作成すると楽でしょう。この点は後述します。

(2)マニフェストファイルを用意しよう

アイコンを用意したら、マニフェストファイルを作成しましょう。マニフェストファイルは、Webアプリの情報を記述したJSON形式のファイルです。次のようなマニフェストファイルを作成して、HTMLからリンクします。

{
  "name": "テストアプリ - TestApp",
  "short_name": "TestApp",
  "description": "PWAのテストアプリです。",
  "icons": [],
  "start_url": "/index.html",
  "display": "standalone",
  "theme_color": "#0000FF",
  "background_color": "#0000FF"
}

上記のファイルを「manifest.json」という名前で保存しましょう。そして、HTMLファイルからリンクします。

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

それでは、ここで実際にアイコンを作成し、マニフェストを自動生成してみましょう。このために、Node.jsを利用します。Node.jsがインストールされていなければ、こちらからインストールしてください。

コマンドライン(WindowsではPowerShell、macOSではターミナル.app)を起動して、以下のコマンドを実行しましょう。これは、pwa-asset-generatorをインストールするものです。

$ npm install -g pwa-asset-generator

そして、ここでは、logo.svgというファイルを元にアイコンを生成しましょう。上記の「manifest.json」および、それをリンクしたHTMLファイル「index.html」を用意した上で、下記のコマンドを実行します。

$ pwa-asset-generator logo.svg icons -m manifest.json -i index.html

すると、iconsというフォルダにいろいろなサイズのアイコンが自動生成されます。そして、自動的にマニフェストファイルとHTMLファイルにリサイズしたアイコンがリンクされます。

  • 自動的に複数サイズのアイコンが生成されたところ

    自動的に複数サイズのアイコンが生成されたところ

(3)Service Workerに対応しよう

Service Workerというのは、ナビゲーションやリソースへのリクエストを制御する機能のことです。ネットワークから取得したリソースをキャッシュするようにしたり、オフラインの時にキャッシュからリソースを返したりと、アプリの振る舞いを変更できます。こうした振る舞いをJavaScriptで記述します。

先ほど、マニフェストをリンクしたHTMLファイル「index.html」に次のようなJavaScriptを追加しましょう。以下のように記述することで、Service Workerである「service-worker.js」を登録します。

<script>
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js').then(reg => {
    console.log('サービスワーカーを登録しました', reg);
  }).catch(err => {
    console.log('登録失敗', err);
  });
}
</script>

そして、実際のService Workerである「service-worker.js」は次のようなファイルを用意します。

// キャッシュしたいファイルの一覧を指定 --- (*1)
const cacheFiles = ['index.html', 'logo.svg'];
const cacheName = 'v1';
// インストール時に実行されるイベント --- (*2)
self.addEventListener('install', event => {
  // キャッシュしたいファイルを指定
  caches.open(cacheName).then(cache => cache.addAll(cacheFiles));
});
// インストール後に実行されるイベント
self.addEventListener('activate', event => {
  // 必要に応じて古いキャッシュの削除処理などを行う
});
// fetchイベント
self.addEventListener('fetch', event => {
  // キャッシュがあればそれを返す --- (*3)
  event.respondWith(
    caches.match(event.request).then(function(resp) {
      return resp || fetch(event.request).then(function(response) {
        let responseClone = response.clone();
        caches.open(cacheName).then(function(cache) {
          cache.put(event.request, responseClone);
        });
        return response;
      });
    }).catch(function() {
      return caches.match('logo.svg');
    }));
});

プログラムを確認してみましょう。(*1)では、ブラウザにキャッシュしたいファイルの一覧を指定します。(*2)の部分でキャッシュしたいファイルを実際に登録します。そして、(*3)では実際にリソースの要求があったときに、何を行うのかを指定する、fetchイベントを記述します。ここでは、(*2)でブラウザにキャッシュしたファイルを返すようにします。

ここまでのindex.htmlファイルは以下のようになります。

<html>
  <head>
    <meta charset="utf-8">
    <title>TestApp</title>
    <link rel="manifest" href="manifest.json">
  <!-- 以下は、自動で追加されたコード -->
    <link rel="apple-touch-icon" href="icons/apple-icon-180.png">
  <!-- 省略... -->
  </head>
  <body>
    <h1>TestApp</h1>
    <img src="logo.svg">
<script>
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js').then(reg => {
    console.log('サービスワーカーを登録しました', reg);
  }).catch(err => {
    console.log('登録失敗', err);
  });
}
</script>
</body></html>

(4)サイトに配置しよう

最後に、ここまでで用意したファイル一式をWebサイトに配置しましょう。メインファイルの「index.html」、そして、マニフェスト「manifest.json」、Service Workerの本体「service-worker.js」とアイコンです。なお、ここまでのファイル一式は、こちらからダウンロードできます。

  • ここまでの作業で用意したファイル一式

    ここまでの作業で用意したファイル一式

そして、ファイル一式をブラウザで見られるようにするには、HTTPSでアクセスできるWebサイト、あるいは、localhostに配置する必要があります。ここでは、テスト用に、localhostを利用してみましょう。

コマンドラインを開いて以下のコマンドを実行しましょう。これは、Node.jsの簡易Webサーバーをインストールするものです。

npm install -g serve

そして、用意したファイル一式のあるディレクトリでで以下のコマンドを実行します。

serve .

すると、Webサーバーが起動するので、画面に表示されるURLにアクセスしましょう。デフォルトでは、http://localhost:3000 です。ブラウザでこのアドレスにアクセスしましょう。すると、サイトが表示されます。

  • 動かしてみたところ

    動かしてみたところ

なお、Google Chromeではページを右クリックして、ポップアップメニューから「検証」をクリックすると、開発者ツールが表示されます。特に「アプリケーション」のタブを開き、Service Workerの項目を確認してみましょう。正しく動いていないようなら「登録解除」のリンクをクリックすると、Service Workerを初期化できます。

そして、正しくサイトが表示されたら、コマンドラインに戻って[Ctrl]+[C]をクリックしましょう。するとサーバーが終了します。サーバーを終了させた後で、ブラウザに戻り、リロードボタンを押してみましょう。サーバーが起動していない状態でも、正しくページが表示されたのを確認できるでしょう。

  • サーバーがダウンしていても無事にブラウザでサイトを見られる

    サーバーがダウンしていても無事にブラウザでサイトを見られる

次に、インストールを試してみましょう。残念ながらlocalhostでインストールの機能を試すことはできません。HTTPS接続が可能なWebサイトにアップロードする必要があります。

ファイル一式を、HTTPSのサイトに配置すると、PWAとしてインストールできるようになります。ここでは、こちらのデモサイトに配置してみました。Google ChromeやMicrosoft Edgeではメニューの「…」からアプリをインストールできます。

  • PWAとして動かすことができた

    PWAとして動かすことができた

まとめ

以上、今回はブラウザから手軽にインストールできるアプリのPWAを作ってみました。これまで通り、HTMLとJavaScriptを使って作成できます。今回紹介したポイントさえ押さえれば、それほど複雑な手順が必要なわけではありません。そのため、既存のWebサイトをPWA対応するのも、それほど難しくありません。PWAにすることで、利便性が飛躍的に向上します。本稿がPWA対応の足がかりになれば幸いです。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。直近では、「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」「すぐに使える!業務で実践できる! PythonによるAI・機械学習・深層学習アプリのつくり方 TensorFlow2対応(ソシム)」「マンガでざっくり学ぶPython(マイナビ出版)」など。