コンテンツへスキップ

PWAの基礎知識(その9)「Push API/VAPID編」

by : 2018/07/27

Webブラウザにプッシュ通知を送れるPush APIは魅力的な機能ですが、各ブラウザによって実装が異なっていたり、Firebaseでプロジェクトを登録したりするのが手間でした。それを共通化し、さらにプロジェクト登録不要で使えるようにする仕組みがVAPIDになります。

今回はこのVAPIDを使ったPush APIの使い方です。

必要なもの

今回はVAPIDに対応したライブラリ、web-pushを使います。今回はNode.jsのライブラリです。zaru/webpushというRuby向けのライブラリもあります。

初期設定

まずサーバ側で秘密鍵と公開鍵を用意します。これは以下のコードで可能です。

const webpush = require("web-push");
JSON.stringify(webpush.generateVAPIDKeys());
// '{"publicKey":"BDC..tP4","privateKey":"Kne…Km8"}'

view raw
index.
hosted with ❤ by GitHub

この内容を application-server-keys.json などとしてサーバに保存しておきます。

JavaScriptの準備

Service Worker

VAPIDを使った場合の魅力として、ペイロードが送れるという点が挙げられます。メッセージ付きで送れるので、クライアントサイドで処理判別ができます。そのための処理をService Worker用のJavaScriptに入れておきます。

self.addEventListener('install', () => {
console.log('ServiceWorker がインストールされました');
});
self.addEventListener('push', ev => {
// payloadの取得
const {title, msg, icon} = ev.data.json();
self.registration.showNotification(title, {
icon: icon,
body: msg
});
self.registration.pushManager.getSubscription().then(subscription => {
console.log(subscription);
}, err => console.log(err));
});

view raw
index.js
hosted with ❤ by GitHub

クライアントサイド

次にクライアントサイドですが、まずService Workerを読み込みます。そして、その後プッシュ通知の登録状態を確認しています。

if (!('serviceWorker' in navigator)) {
// Service Worker非対応
}
navigator.serviceWorker.register('./serviceworker.js')
.then(() => {
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
// プッシュ通知がサポートされていない場合
return;
}
if (Notification.permission === 'denied') {
// プッシュ通知を拒否された場合
return;
}
if (!('PushManager' in window)) {
// PushManagerが存在しない場合
return;
}
return navigator.serviceWorker.ready;
})
.then(serviceWorkerRegistration => {
return serviceWorkerRegistration.pushManager.getSubscription();
})
.then(subscription => {
if (!subscription) {
// すでに購読中
} else {
// 未購読
console.log(subscription.toJSON());
}
})

view raw
index.js
hosted with ❤ by GitHub

購読を開始する際のイベントは次の通りです。大事なポイントとして、 applicationServerKey を追加しています。ここには公開鍵をunit8にしたものを適用します(後述)。

navigator.serviceWorker.ready
.then(serviceWorkerRegistration => {
return serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
})
.then(subscription => {
// 購読開始
console.log(subscription.toJSON());
})

view raw
index.js
hosted with ❤ by GitHub

公開鍵の設定です。 vapidPublicKey には web-push で生成した公開鍵を指定します。

const vapidPublicKey = 'BOO…YEk';
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
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;
}

view raw
index.js
hosted with ❤ by GitHub

Web Pushの購読データ(subscription)をJSON出力すると、次のような内容になっています。このデータをすべて保存しておきます(サーバなど)。

{
"endpoint":"https://fcm.googleapis.com/fcm/send/e7K…Hag&quot;,
"expirationTime":null,
"keys":{
"p256dh":"BK7…e5U",
"auth":"DGt…D8g"
}
}

view raw
index.
hosted with ❤ by GitHub

Web Pushを送る

ではサーバからプッシュ通知を送ってみましょう。コードは以下のようになります。まず鍵の設定と受信者を指定します。

const webpush = require("web-push");
const keys = require("./application-server-keys.json");
webpush.setVapidDetails(
"mailto:admin@moongift.jp",
keys.publicKey,
keys.privateKey
);
const subscribers = [
{
"endpoint":"https://fcm.googleapis.com/fcm/send/e7K…Hag&quot;,
"expirationTime":null,
"keys":{
"p256dh":"BK7…e5U",
"auth":"DGt…D8g"
}
}
];

view raw
index.js
hosted with ❤ by GitHub

そしてプッシュ通知を送ります。 icon で表示するアイコンを指定しています。

const icon = `app.png`;
const params = {
title: "プッシュ通知です!",
msg: `これはサーバから送っています. 今は ${new Date().toLocaleString()} です。 メッセージとアイコンも送っています `,
icon: icon
};
Promise.all(subscribers.map(subscription => {
return webpush.sendNotification(subscription, JSON.stringify(params), {});
}))
.then(res => console.log(res))
.catch(err => console.log('ERROR', err));

view raw
index.js
hosted with ❤ by GitHub

そしてGoogle ChromeやFirefoxに対して通知が送れます。

Firefoxの場合です。


VAPIDを使った場合の利点としては、Firebaseでプロジェクトを作る手間がなく、Webブラウザの共通仕様の基で開発できるということです。なお、Safariはこの仕様に則っていない(そもそも独自仕様)ので、対応できません。

From → HTML5

コメントは受け付けていません。

%d人のブロガーが「いいね」をつけました。