📤

Service Wokerを使って簡単にWEB Push通知を実装する②

2023/10/15に公開

はじめに

前回の記事 Service Wokerを使って簡単にWEB Push通知を実装する①では、Service Workerの説明とWEB Push通知の全体像についてご説明しました。今回は、Service WorkerとPush通知のNodejsのライブラリweb-pushを使用して、WEBのPush通知をさくっと実装してみたいと思います。
10分ほどで実装できると思うので、ぜひ最後までご覧ください。

①Service Wokerの登録

まず、service-worker.jsという名前のファイルを作成し、次のように記載します。

self.addEventListener('push', event => {
  const options = {
    body: event.data.text(),
    icon: 'icon.png',  // 任意: アイコン画像のパス
    badge: 'badge.png'  // 任意: バッジ画像のパス
  };

  event.waitUntil(
    self.registration.showNotification('Push通知タイトル', options)
  );
});

次に、app.jsという名前のファイルを作成し、次のように記載します。

if ('serviceWorker' in navigator && 'PushManager' in window) {
  navigator.serviceWorker.register('service-worker.js')
    .then(function(swReg) {
      console.log('Service Workerが登録されました', swReg);

      return swReg.pushManager.getSubscription()
        .then(function(subscription) {
          if (subscription === null) {
            const vapidPublicKey = 'PUBLIC_VAPID_KEYを入力してください';
            const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);

            return swReg.pushManager.subscribe({
              userVisibleOnly: true,
              applicationServerKey: convertedVapidKey
            }).then(subscription => {
              console.log('新規に購読開始します');
              console.log(JSON.stringify(subscription));  // 新しい購読情報をコンソールに出力
            });
          } else {
            // 既に購読済み
            console.log('既に購読済みです');
            console.log(JSON.stringify(subscription));  // 購読情報をコンソールに出力
          }
        });
    })
    .catch(function(error) {
      console.error('Service Workerエラー', error);
    });
}

function urlBase64ToUint8Array(base64String) {
  const padding = '='.repeat((4 - base64String.length % 4) % 4);
  const base64 = (base64String + padding)
    .replace(/-/g, '+')
    .replace(/_/g, '/');
  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

さらに、index.htmlを作成し、app.jsを読み込むように記述します。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Push Notification Sample</title>
  <script defer src="app.js"></script>
</head>

<body>
  <h1>Push Notification Sample</h1>
</body>

</html>

ここでは、次のようなことをやっています。
service-worker.jsをService Workerとして登録します。
Push通知の購読を確認し、既に購読が開始していない場合は新しく購読情報を作成します。

ここでは、vapidPublicKeyの箇所に、実際のVAPIDキーを生成したものを記載する必要があります。
VAPIDキーの説明と生成方法については後述します。

②VAPIDキーの生成

VAPIDキーとは?

VAPID(Voluntary Application Server Identification)キーは、Web Pushプロトコルで使用される認証メカニズムの一種です。VAPIDキーは、アプリケーションサーバーを識別し、Push通知サービスに対してそのサーバーの身元を示すために使用されます。この認証メカニズムにより、Push通知サービスは、通知の送信元が正当であることを確認し、悪意のあるアクターによる通知の送信を防ぐことができます。

VAPIDキーは下記の2つの部分から構成されています。

Public Key:
Public Keyは、アプリケーションサーバーの身元を識別するために使用されます。Public Keyはクライアント側で利用され、Push購読を作成する際にPush通知サービスに提供されます。

Private Key:
Private Keyは、アプリケーションサーバー側で保持され、Push通知を送信する際に使用されます。Private Keyは、VAPID認証情報を生成し、Push通知サービスに対して通知の送信元が正当であることを示すために使用されます。

VAPIDキーの生成方法

VAPIDキーの生成とサーバーサイドからのPush通知の送信には、web-pushというNode.jsのライブラリを使用します。

まず、web-pushライブラリをインストールし、VAPIDキーを生成します。
※MacでNodeやnpmを使用する際は、nvmやVolta,node-envなどのバージョン管理ツールを使用してMacにNodeをインストールしている必要があります。

# npmの初期設定(基本すべてEnterでOK)
npm init

# web-pushのインストール
npm install web-push -g

# vapidの生成
web-push generate-vapid-keys

public keyとprivate keyが生成されるので、安全な場所に控えてください。
app.jsのvapidPublicKeyの箇所にpublic keyを貼り付けてください。

③Node.jsでサーバーサイドのコードを作成

次に、サーバーサイドでPush通知を送信するためのコードを作成します。server.jsという名前のファイルを作成して次のように記載してください。

const webpush = require('web-push');

// VAPID keys
const vapidKeys = {
  publicKey: '生成したpublic keyを入力',
  privateKey: '生成したprivate keyを入力'
};

webpush.setVapidDetails(
  'mailto:sample-email@example.com', // アプリ運営者のメールアドレス
  vapidKeys.publicKey,
  vapidKeys.privateKey
);

// PushSubscription
const pushSubscription = {
  endpoint: 'ENDPOINTを記載してください',
  keys: {
    p256dh: 'P256DH_KEYを記載してください',
    auth: 'AUTH_KEYを記載してください'
  }
};

const payload = 'Push通知メッセージ(サンプル)';

webpush.sendNotification(
  pushSubscription,
  payload
).catch(error => {
  console.error(error.stack);
});

ここでは、次のようなことを行っています。

  1. web-pushライブラリをインポートし、VAPIDキーを設定
  2. Push通知の購読情報を設定。これは、クライアントサイドでPush通知の購読を作成時に得られたものを記載。
  3. webpush.sendNotificationメソッドを使ってPush通知を送信します。

2の「Push通知の購読情報を設定」では、クライアント側で購読を開始した際に得られた購読情報(endpointおよびp256dh, authなどのkey情報)を設定します。

よくある実装としては、購読開始時に得られた情報をサーバー側に送って、データベースなどに情報を保存して利用する通知の際に利用するといった方法がありますが、今回はさくっと実装したいので、クライアント側で購読情報をコンソールに表示させて、購読情報をコピーしてサーバー側のソースコードの購読情報の箇所に貼り付けて簡易的にWEB Push通知を試したいと思います。

④WEB Push通知の確認

ローカルサーバーのセットアップ

まず、ローカルでWebサーバーをセットアップする必要があります。
Nodeのライブラリのhttp-serverをインストールします。

コマンドラインから、今回のサンプルアプリケーションのルートディレクトリで次のコマンドを実行します。

npm install -g http-server

続いて、ローカルサーバーを起動します。

http-server

これで、ローカルホストでWebアプリケーションにアクセスできるようになります。

ブラウザでWebアプリケーションにアクセス

ブラウザを開き、ローカルサーバーのURLにアクセスします。
Webアプリケーションが読み込まれて、Push通知の許可を求めるられるので許可しましょう。

Push通知許可ダイアログ

購読情報の取得

購読情報がコンソールに表示されているはずなので、それをコピーして、必要な項目(endpoint, keys)をサーバーサイドのコード(server.js)のpushSubscriptionオブジェクトにペーストします。

サーバーサイドのPush通知のコードを実行

コマンドラインでサーバーサイドのコードを実行します

node server.js

これで、Push通知が送信され、ブラウザで通知が表示されます。

ユーザーが通知の許可設定を解除したり、キャッシュをクリアしない限りは、Service Workerの購読が継続されるため、必要に応じて購読解除処理やエラーハンドリングを入れてあげる必要があります。

まとめ

今回は、Service WorkerとNodeのライブラリのweb-pushを使用して、簡単にWEB Pushを実装するハンズオンをまとめました。購読情報のサーバーへの送信処理やDB保存処理などは省略してますが、WEBのPUSH通知の全体像をお手軽に把握していただけたかと思います。今回は、通知を行うサーバー側の処理もJavaScriptで実装しましたが、ほかの言語でもWEB Push通知は実装できるので試してみてください。
今後、Push通知がWEBからもできることで、Push通知のためにネイティブアプリを実装することは不要になってっくると思います。Push通知がWEBでも可能=ネイティブアプリが不要ということにはならないと思いますが、WEBサービスはPWA化&WEB Push通知を利用することで暫定のモバイル対応を行うのが主流になるかもしれませんね。本記事が誰かのお役に立てると幸いです。

Discussion