Angularでプッシュ通知対応ページを作成
以下では、プッシュ通知を受信する「Webページ」を、AngularのPWA機能を利用して作成します。また、プッシュ通知を送信する「サーバー」を、Node.jsとライブラリーで作成して、実際にプッシュ通知を送信してみます。
プロジェクトの作成
まず、Webページとサーバーのプロジェクトを作成します。WebページのAngularプロジェクトは、前回記事で説明した方法で作成して、PWA機能が利用できるようにします。
サーバーを実装するNode.jsプロジェクトは、リスト1のコマンドで作成します。(1)で空のプロジェクトフォルダーを作成して(2)でそのフォルダーに移動し、(3)の「npm init」コマンドでプロジェクトを作成します。いくつか質問されますが、すべて改行キーを押して、デフォルト値を受け入れます。プロジェクト作成後、(4)でプッシュ通知ライブラリー「web-push」をインストールします。
mkdir p002-push-server # プロジェクトフォルダー作成 ...(1) cd p002-push-server # プロジェクトフォルダーに移動 ...(2) npm init # プロジェクト作成 ...(3) npm install --save web-push # プッシュ通知ライブラリーをインストール ...(4)
プッシュ通知登録の実装
作成したプロジェクトに、プッシュ通知登録の処理を実装していきます。まず、サーバーのプロジェクトにJavaScriptファイルを追加して、リスト2の通り実装します。この処理は、プッシュ通知で使うサーバーの鍵ペア(公開鍵と秘密鍵)を生成するもので、(1)で参照したweb-pushライブラリーの変数webpushを利用して、(2)のgenerateVAPIDKeysメソッドで鍵ペアを生成します。
const webpush = require('web-push'); // web-pushを参照 ...(1) // サーバーの鍵ペアを生成(一度だけ実行) ...(2) const vapidKeys = webpush.generateVAPIDKeys(); console.log('publicKey:', vapidKeys.publicKey); console.log('privateKey:', vapidKeys.privateKey);
リスト2を「node generatekeys.js」コマンドで実行すると、図3のようにコンソールに鍵ペアが出力されるので、値を控えておきます。なお、鍵ペアは1回生成すれば、継続して利用できます。
次に、WebページのAngularプロジェクトで、ルートコンポーネント(app.component.ts)のコンストラクターに、プッシュ通知登録の処理をリスト3の通り実装します。
// サーバー公開鍵 ...(1) vapidPublicKey = '<生成したサーバー公開鍵>'; // コンストラクター ...(2) constructor(private swpush: SwPush) { // プッシュ通知登録の処理 ...(3) this.swpush.subscription.subscribe(pushSubscription => { if (pushSubscription == null) { // 登録がない場合、新規に登録 ...(4) this.swpush.requestSubscription({ serverPublicKey: this.vapidPublicKey // サーバー公開鍵を指定 ...(5) }); } else { // すでに登録がある場合 ...(6) // エンドポイント(プッシュ通知送信時にアクセスするURL)...(7) console.log("endpoint:", pushSubscription.toJSON().endpoint); // クライアント公開鍵/Auth Secret(通知の暗号化に利用)...(8) console.log("publicKey:", pushSubscription.toJSON().keys.p256dh); console.log('authSecret:', pushSubscription.toJSON().keys.auth); } }); (略) }
(1)はリスト2で生成したサーバー公開鍵です。(2)のコンストラクターで、Angularのプッシュ通知関連機能を提供するSwPushのオブジェクトを、依存性注入でswpush変数に受け取ります。
(3)で、プッシュ通知登録の処理を行います。this.swpush.subscriptionは、プッシュ通知が登録されていないときはnull、登録されているときは登録内容のオブジェクトを、pushSubscription引数に設定してイベントを発生します。
(4)のようにpushSubscriptionがnullの場合は、プッシュ通知がまた登録されていないため、this.swpush.requestSubscriptionメソッドで新規登録します。このとき(5)のように、サーバー公開鍵をパラメーターに指定します。
プッシュ通知登録が完了したか、すでに登録済みの場合(6)は、(7)のエンドポイント(プッシュ通知送信APIのURL)と、(8)のクライアント公開鍵/Auth Secretを、登録内容を表すpushSubscriptionから取得します。いずれもサーバーがプッシュ通知を送信するときに必要な情報で、本来ならサーバーに送信しますが、このサンプルではコンソールに出力させています。
[補足]複数の意味がある「Subscribe」に注意
Webプッシュ通知の登録を行うことを「Subscribe」と呼びます。また、Angularで利用されるJavaScript版Reactive Extensions(RxJS)で、イベントを受け取るための登録処理も「Subscribe」と呼びます。リスト3ではこれら両方のSubscribeが混在しています。
例えば、リスト3(3)の「this.swpush.subscription.Subscribe」メソッドは、プッシュ通知登録時にイベントを発生する、RxJSのObservable「this.swpush.subscrition」に対して、RxJSのSubscribeメソッドを実行して、プッシュ通知登録のイベントを受け取るようにしています。
一方で、リスト3(3)のイベント変数「pushSubscription」や、(4)の「this.swpush.requestSubscription」メソッドの「Subscription」は、Webプッシュ通知の登録を意味しており、RxJSとは関係ありません。
[補足]Webプッシュ通知で利用する鍵
リスト2で生成したサーバー鍵ペアは、プッシュサービスが送信元サーバーの正当性を判定するために利用します。プッシュ通知送信時、サーバーは自身の秘密鍵で作成した署名をプッシュサービスに渡して、プッシュサービスではサーバー公開鍵で署名を検証します。この仕組みをVAPID(Voluntary Application Server Identification)と呼びます。
一方で、リスト3(8)のクライアント公開鍵とAuth Secretは、プッシュ通知の内容(ペイロード)を暗号化するために利用します。
今回のサンプルでは、これらの検証や暗号化に関連した処理は、web-pushライブラリーが内部的に実行しています。より詳しい処理内容については、Googleが公開している技術文書を参照してください。
リスト3の実装後、「npm run pwa」コマンドを実行してビルドとWebサーバー起動を行って、Webブラウザーで「http://localhost:8080」にアクセスします。初回のページ表示時に、通知の許可を求めるブラウザーのダイアログが表示されます。
図4のダイアログで「許可」をクリックすると、エンドポイントと、クライアント公開鍵/Auth Secretがコンソールに出力されます。プッシュ通知の送信時に利用するので、これらの値を控えておきます。
[補足]通知をブロックしてしまったら
図4のダイアログで「ブロック」をクリックしてしまった場合は、Chromeの設定画面を表示して、「コンテンツの設定」-「通知」で設定を削除してください。削除後にページを再表示すると、図4のダイアログがもう一度表示されます。
プッシュ通知送信の実装
ここでは、サーバーからプッシュ通知を送信する処理を実装します。サーバーのプロジェクトにJavaScriptファイルを追加して、リスト4の通り実装します。
const webpush = require('web-push'); // web-pushを参照 // サーバー鍵ペア ...(1) const vapidPublicKey = '<サーバー公開鍵>'; const vapidPrivateKey = '<サーバー秘密鍵>'; // 通知に必要なパラメーター ...(2) const endpoint = '<エンドポイント>'; const p256dh = '<クライアント公開鍵>'; const auth = '<Auth Secret>'; // web-pushライブラリーに検証のための情報を設定 ...(3) webpush.setVapidDetails( 'mailto:<連絡先メールアドレス>', vapidPublicKey, vapidPrivateKey ); // pushSubscription(プッシュ通知送信先情報)を作成 ...(4) const pushSubscription = { endpoint: endpoint, keys: { p256dh: p256dh, auth: auth } }; // プッシュ通知送信 ...(5) webpush.sendNotification( pushSubscription, JSON.stringify({ notification: { title: 'あなただけにお得なお知らせ', body: '年に一度の限定セールがスタート! 今すぐWebページでチェック!', icon: 'assets/icons/icon-192x192.png' } }) );
(1)はサーバー鍵ペア、(2)はプッシュ通知登録時にWebページが取得したエンドポイント、クライアント公開鍵、Auth Secretです。(3)では、web-pushライブラリーの変数webpushに、サーバーの連絡先情報とサーバー鍵ペアを設定します。連絡先情報は「mailto:」+メールアドレス、またはWebページのURLを設定します。
(5)のwebpush.sendNotificationが、プッシュ通知送信の処理です。第1引数は送信に必要な(2)の情報を(4)の通りまとめたオブジェクト、第2引数は通知内容(ペイロード)で、JSON文字列形式で指定します。ここでは通知内容を表すnotificationオブジェクトに、title(タイトル)、body(本文)、icon(アイコン)を指定しています。
リスト4を「node sendnotification.js」コマンドで実行するとプッシュ通知が送信され、Webページが受信したプッシュ通知の内容が図7のように画面右下に表示されます。ここではプッシュ通知送信の処理をコマンドで実行していますが、実際にWebプッシュ通知を本番環境で利用する場合、お知らせのプッシュ通知を送信したいタイミングでリスト4の処理を行うよう、プッシュ通知を送信するサーバーを実装することになります。
なお、一般にWebプッシュ通知を表示する処理は、開発者がService Workerに実装する必要がありますが、AngularのPWA対応機能では、Webプッシュ通知対応のService Workerが自動的に生成されます。