SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

次世代Webアプリケーションフレームワーク「Angular」の活用

AngularのPWA(Progressive Web Apps)機能でWebプッシュ通知を実装

次世代Webアプリケーションフレームワーク「Angular」の活用 第17回

  • X ポスト
  • このエントリーをはてなブックマークに追加

Angularでプッシュ通知対応ページを作成

 以下では、プッシュ通知を受信する「Webページ」を、AngularのPWA機能を利用して作成します。また、プッシュ通知を送信する「サーバー」を、Node.jsとライブラリーで作成して、実際にプッシュ通知を送信してみます。

プロジェクトの作成

 まず、Webページとサーバーのプロジェクトを作成します。WebページのAngularプロジェクトは、前回記事で説明した方法で作成して、PWA機能が利用できるようにします。

 サーバーを実装するNode.jsプロジェクトは、リスト1のコマンドで作成します。(1)で空のプロジェクトフォルダーを作成して(2)でそのフォルダーに移動し、(3)の「npm init」コマンドでプロジェクトを作成します。いくつか質問されますが、すべて改行キーを押して、デフォルト値を受け入れます。プロジェクト作成後、(4)でプッシュ通知ライブラリー「web-push」をインストールします。

[リスト1]サーバーのNode.jsプロジェクトを作成するコマンド
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メソッドで鍵ペアを生成します。

[リスト2]サーバーの鍵ペアを作成する処理(p002-push-server/generatekeys.js)
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回生成すれば、継続して利用できます。

図3 生成されたサーバーの鍵ペア(p002-push-server/generatekeys.js)
図3 生成されたサーバーの鍵ペア(p002-push-server/generatekeys.js)

 次に、WebページのAngularプロジェクトで、ルートコンポーネント(app.component.ts)のコンストラクターに、プッシュ通知登録の処理をリスト3の通り実装します。

[リスト3]Webページのプッシュ通知登録処理(p001-push-client/src/app/app.component.ts)
// サーバー公開鍵 ...(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 通知の許可を求めるダイアログ(p001-push-client)
図4 通知の許可を求めるダイアログ(p001-push-client)

 図4のダイアログで「許可」をクリックすると、エンドポイントと、クライアント公開鍵/Auth Secretがコンソールに出力されます。プッシュ通知の送信時に利用するので、これらの値を控えておきます。

図5 コンソールへの出力内容(p001-push-client)
図5 コンソールへの出力内容(p001-push-client)

[補足]通知をブロックしてしまったら

 図4のダイアログで「ブロック」をクリックしてしまった場合は、Chromeの設定画面を表示して、「コンテンツの設定」-「通知」で設定を削除してください。削除後にページを再表示すると、図4のダイアログがもう一度表示されます。

図6 Chrome設定画面で通知設定を削除
図6 Chrome設定画面で通知設定を削除

プッシュ通知送信の実装

 ここでは、サーバーからプッシュ通知を送信する処理を実装します。サーバーのプロジェクトにJavaScriptファイルを追加して、リスト4の通り実装します。

[リスト4]プッシュ通知送信の実装(p002-push-server/sendnotification.js)
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の処理を行うよう、プッシュ通知を送信するサーバーを実装することになります。

図7 プッシュ通知の表示(p001-push-client)
図7 プッシュ通知の表示(p001-push-client)

 なお、一般にWebプッシュ通知を表示する処理は、開発者がService Workerに実装する必要がありますが、AngularのPWA対応機能では、Webプッシュ通知対応のService Workerが自動的に生成されます。

次のページ
Webプッシュ通知機能のカスタマイズ

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
次世代Webアプリケーションフレームワーク「Angular」の活用連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11278 2018/12/19 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング