• 虹色ミツバチ
  • freoカスタマイズメモ、テンプレート・プラグイン配布/officeTIPS
検索プラグイン
虹色ミツバチ

> Entry >Other>CSS / jQuery / javascript> PWAでプッシュ通知を実装してみる(2)とりあえずPWA化するためのmagnifest.jsonとserviceworker

【Other】【CSS / jQuery / javascript】PWAでプッシュ通知を実装してみる(2)とりあえずPWA化するためのmagnifest.jsonとserviceworker

PWAでプッシュ通知を実装してみる(2)とりあえずPWA化するためのmagnifest.jsonとserviceworker

前回の記事ではPWAでプッシュ通知を実装することにした経緯とかざっくりした方法と結果を説明しました。
今回はPWA部分に的を絞って書いていきます。

PWAとは

前回も解説しましたが、PWAとは Progressive Web Apps の略です。
Googleが推進しているウェブをアプリみたいに利用できる機能のことです。

詳しくは前回の記事をご覧ください。

PWA化に必要なもの

PWA化するにあたり、下記のものが必要になります。

  • サイトの全体SSL化
  • 192x192pxと512×512pxのアイコン画像
  • manifest.json
  • serviceworker.js
  • headタグの編集

全体SSL化とアイコン画像はまだしも、magnifest.jsonとserviceworker.jsは無いと思うので、作り方も含めて解説します。

サイト全体のSSL化

頑張ってください。

アイコン画像

192x192px、512x512pxのpng画像があればOKです。
サイトのルートディレクトリに設置してください。

magnifest.json

ウェブアプリのマニフェストをjson形式で記載したものです。
ウェブアプリをインストールする際にこちらの設定が参照されます。

magnifest.jsonはサイトのルートディレクトリに設置します。
また、サイトのheadタグ内にmagnifest.jsonの位置を記載しておく必要があります。

HTMLの記述

サイトのheadタグ内に下記のように記載してください。

    <link rel="manifest" href="/manifest.json">
 magnifest.jsonの記述

magnifest.jsonはjson形式で記載します。
AdobeXDのリファレンスを見ると様々な項目を設定することができますが、当サイトではとりあえず下記のように書いてみました。
適当に改変して使用してください。

{
    "name": "虹色ミツバチ-32877",
    "short_name": "32877",
    "description": "freoカスタマイズメモ、テンプレート・プラグイン配布/officeTIPS",
    "start_url": "/?utm_source=homescreen&utm_medium=pwa",
    "display": "standalone",
    "lang": "ja",
    "dir": "auto",
    "orientation": "any",
    "theme_color": "#bcb782",
    "background_color": "#fffce0",
    "icons": [
        {
            "src": "/pwa_192.png",
            "type": "image/png",
            "sizes": "192x192"
        },
        {
            "src": "/pwa_512.png",
            "type": "image/png",
            "sizes": "512x512"
        }
    ],
    "gcm_sender_id": "103953800507"
}

なお、それぞれの項目は

name サイト(ウェブアプリ)名
short_name ホーム画面に表示されるサイト(ウェブアプリ)名
description サイト(ウェブアプリ)の説明
start_url 起動時に表示されるURL。
PWA化するならこのままでOK。
display 表示モード。
fullscreen、fullscreen、standalone、minimal-uiの4つを設定可能。
通常はstandaloneでOK。
lang 日本語なら「ja」
dir テキストの方向。
ltr(左から右)、rtl(右から左)、autoの3つを設定可能。
日本語はltr(左から右)でOK。
theme_color サイト(ウェブアプリ)のテーマカラー。
OS/ブラウザによって使用方法は異なる。
background_color 背景色。
サイト起動時にこの色が表示されたりする。
icons アイコン用画像。
ホーム画面に表示されたりする。
192x192pxと512x512pxがあればOK。
gcm_sender_id プッシュ通知を受信する場合は必要です。
いらない場合は削ってOKです。
FirebaseのCloud Messagingでプッシュ通知を受信する場合は、挿入値は「103953800507」固定になります。
設置箇所

magnifest.jsonの編集が終わったら、サイトのルートディレクトリに設置してください。

serviceworker.js

serviceworker.jsはウェブアプリをバックグラウンドで実行するスクリプトです。
オフラインのアプリの実現・サポートを行い、キャッシュ機能で画面の表示速度を上げます。

なお、serviceworker.jsのファイル名は[serviceworker]で固定である必要はありません
また、複数のserviceworkerを使用するより、一つのjsファイルにまとめたほうが良いようです。

serviceworker.jsはサイトのルートディレクトリに設置します。
また、サイトのheadタグ内にserviceworker.jsの位置や使用するタイミングなどを記載しておく必要があります。

serviceworker.jsの書き方

serviceworkerの書き方は色々調べましたが、ここが一番参考になる+理想通りに動きました。

Qiita:Service Workerの基本とそれを使ってできること

上記を参考に書いて当サイトで動いているserviceworkerの一部がこちら↓

const VERSION = "1";
const ORIGIN = location.protocol + '//' + location.hostname;

const STATIC_CACHE_KEY = 'static-' + VERSION;
const STATIC_FILES = [
    ORIGIN + '/',
    ORIGIN + '/images/logo.png',
    ORIGIN + '/css/bootstrap.min.css',
    ORIGIN + '/css/bootstrap-reboot.min.css',
    ORIGIN + '/css/common.css',
    ORIGIN + '/css/default.css',
    ORIGIN + '/js/jquery.js',
    ORIGIN + '/js/common.js',
];
const CACHE_KEYS = [
    STATIC_CACHE_KEY
];

self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(STATIC_CACHE_KEY).then(cache => {
            return Promise.all(
                STATIC_FILES.map(url => {
                    return fetch(new Request(url, { cache: 'no-cache', mode: 'no-cors' })).then(response => {
                    return cache.put(url, response);
                    });
                })
            );
        })
    );
});

self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then((cacheNames) => {
            return cacheNames.filter((cacheName) => {
                // STATIC_CACHE_KEYではないキャッシュを探す
                return cacheName !== STATIC_CACHE_KEY;
            });
            }).then((cachesToDelete) => {
            return Promise.all(cachesToDelete.map((cacheName) => {
                // いらないキャッシュを削除する
                return caches.delete(cacheName);
            }));
        })
    );
});

self.addEventListener('fetch', event => {
    // POSTの場合はキャッシュを使用しない
    if ('POST' === event.request.method) {
        return;
    }

    event.respondWith(
        caches.match(event.request)
        .then((response) => {
            // キャッシュ内に該当レスポンスがあれば、それを返す
            if (response) {
                return response;
            }

          // 重要:リクエストを clone する。リクエストは Stream なので
          // 一度しか処理できない。ここではキャッシュ用、fetch 用と2回
          // 必要なので、リクエストは clone しないといけない
            let fetchRequest = event.request.clone();

            return fetch(fetchRequest)
            .then((response) => {
                if (!response || response.status !== 200 || response.type !== 'basic') {
                    // キャッシュする必要のないタイプのレスポンスならそのまま返す
                    return response;
                }

                // 重要:レスポンスを clone する。レスポンスは Stream で
                // ブラウザ用とキャッシュ用の2回必要。なので clone して
                // 2つの Stream があるようにする
                let responseToCache = response.clone();

                caches.open(STATIC_CACHE_KEY)
                .then((cache) => {
                    cache.put(event.request, responseToCache);
                });

                return response;
            });
        })
    );
});

今回はあくまでプッシュ通知を目標にするため、上記タグだけでは不十分ですが、キャッシュの生成・削除までの一連の流れは上記でまかなえます。

上記サンプルserviceworkerのざっくりした解説

1行目がキャッシュの番号です。
サイトを更新するたびにこの番号を増やしていく必要があります。

PWAのサイトはだいぶキャッシュが強いです。
serviceworkerでサイトの更新を明示することにより、キャッシュを増やし古いキャッシュを削除します。
そのため、CMSなどを利用したサイトでは「コメントが増えた時」や「新規投稿を行った時」などにserviceworkerを自動的に更新するしくみが必要だと思います。

現時点で、当サイトでは手動でserviceworkerを更新しています。
そのうちfreo用のPWA化用プラグインを作ってみようとは思ってますが、そのうち。
WordpressではPWA化用プラグインがあるようなのでWordpressの方は検討してみてください。
Wordpress用のPWA化プラグインでこれ以降に解説するプッシュ通知が使えるかどうかは実証してません。

5~14行目でキャッシュ化するファイルを指定しています。
URLだけでなくjQueryやスタイルシート等も入れておくと読み込みが早くなるでしょう。

19行目以下でキャッシュの作成・利用・削除などを行っています。
この辺は先程紹介したQiitaの記事で解説されています。

serviceworker.jsを登録する

serviceworker.jsは作成しルートディレクトリに設置しただけでは動きません。
serviceworker.jsをサイトに登録するため、headタグ内に下記のように記載してください。

<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/serviceworker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}
</script>

このコードは、Service Worker APIが利用可能かどうかを確認し、利用可能な場合は、ページが読み込まれたときに 、 /service-worker.jsのService Workerが登録されます。(参考:はじめてのプログレッシブウェブアプリ

ただし、今回はあくまでプッシュ通知を目標にするため、上記タグだけでは不十分ですが、それでもserviceworkerが実際活躍するかどうかの確認をするなら上記タグだけでもOKです。

serviceworkerで作成したキャッシュの確認方法

キャッシュが正常に動いているかどうかは、GoogleChromeのデベロッパーツールで確認できます。
F12キーでデベロッパーツールを開き、ApplicationタブのCache Storageを見ると、現時点で使用されているキャッシュが表示されます。

2019072901.jpg

serviceworkerで[37]を指定しているため、キャッシュが[37]に登録されています。
管理者がserviceworkerを[38]に変更して更新すると、キャッシュが再生成されます。

正常にキャッシュの作成・削除ができていると、Cache Storageには1つのキャッシュしか保持されません。
[37][38][39]…のように複数のキャッシュが存在する場合、キャッシュの削除に失敗しています。
また、serviceworkerが指定している数字(例えば[37])と違う番号のキャッシュが作成されている場合(例えば[39]など)もキャッシュの作成に失敗しているので注意してください。

特定の画面をキャッシュしない処理

特定のURLをキャッシュしたくない場合、fetchイベント内(上記の例でいうと60行目と61行目の間)に下記のように記載してください。

    // 管理画面はキャッシュを使用しない
    if (/\/admin|\/login|\/user/.test(event.request.url)) {
        return;
    }

上記の例では、

  • http://サイトURL/admin
  • http://サイトURL/login
  • http://サイトURL/user

上記URLでキャッシュを使用しないようにしています。

管理者が作成したコンテンツを表示するのみの画面はキャッシュを利用して構いませんが、閲覧者の操作によってリアルタイムで動的に内容が変更する可能性のある画面はキャッシュを利用しないほうがベターです。

headタグの記載について

PWA化する時、magnifest.jsonとserviceworker.jsの箇所でちょろっと書きましたが、headタグ内にPWA化用のソースを記載する必要があります。

まとめるとこんな感じです。

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#6a5f80"/>
<meta name="apple-mobile-web-app-title" content="32877">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" href="/pwa_512.png" sizes="512x512">
<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/serviceworker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}
</script>

PWAはGoogleが主体となって広がっている新たな機能なので、iOSではまだ未実装な部分があり、iOSでPWAを使用する場合にはメタタグで各種設定を指定する必要があります。

今回のまとめ

今回はプッシュ通知のことはとりあえず置いておいてサイトをPWA化する時に最低限必要なものだけご紹介しました。
今回の記事にあるようにmagnifest.jsonとserviceworker.jsを設置したりして色々やれば、サイトをインストールできるようにしたり、表示を早めたりすることは可能です。

PWA化については他にもいろんなサイトや本で紹介されているので、そちらも併せて参考にしてください。
次回は、いよいよプッシュ通知を送るためのあれこれについて解説していきたいと思います。

ページ移動

関連記事

ページ上部へ