ServiceWorker について(2)
目標
ServiceWorker でPush通知を受け取る。
内容的には下記の記事の続き。
目次
尚、参考はこれ
フレームワークインストール
まずは nodejs
でサーバを作る。
npm init
とだけ打ち込んで空のパッケージを作成する。
次にフレームワークをインストールしよう
npm i compression
npm i express
npm i web-push
コレだけですし、一瞬ですかね?
実装
こんな感じの配置でファイルを作る
- root
- public
- js
vapid_demo.js
: 初期化等諸々
index.html
: 画面sw.js
: サービスワーカー
- js
index.js
: エントリポイントpackage.json
: nodejs の管理ファイル
- public
各ファイルの実装
index.js
シンプルに実装
const compression = require('compression'); const express = require('express'); const webPush = require('web-push'); const app = express(); const port = 3000; // サーバ起動時に、秘密鍵と公開鍵を作成 const vapidKeys = webPush.generateVAPIDKeys(); // Push 通知機能を初期化 webPush.setVapidDetails( 'mailto:xxxxxxx@xxxxx.example', // メール形式でどうぞ vapidKeys.publicKey, vapidKeys.privateKey ); app.use(compression()); app.use(express.json()); // 公開鍵を応答するアクション app.get('/key', (req, res) => { res.status(200).send(vapidKeys.publicKey); }) // POST を受けたら、5秒後に Push 通知を送信するアクション app.post('/webpushtest', (req, res) => { console.log(req.body); try { setTimeout(async _ => { // ちょっと遅延させて通知 await webPush.sendNotification(req.body, JSON.stringify({ title: 'Web Push通知テスト', })); }, 5000); res.json({ success: true }); } catch (err) { console.log(err); } }) // 上記URLでヒットしないなら、public の中を表示する app.use('/', express.static('public')); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
index.html
こっちも死ぬほどシンプル
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>VAPID WebPush Demo</title> </head> <body> <button id="btnWebPushTest">プッシュ通知テスト</button> <script src="js/vapid_demo.js"></script> </body> </html>
vapid_demo.js
Push 通知を受け取るための初期化を行ってるコード。
因みに、ここの subscription
をサーバ側に保存することで、個別に Push 通知出来るっぽい。
let convertedVapidKey, subscription; (async _ => { try { const registration = await navigator.serviceWorker.register('/sw.js', { scope: '/' }); // サーバー側で生成したパブリックキーを取得し、urlBase64ToUint8Array()を使ってUit8Arrayに変換 const res = await fetch('/key'); const vapidPublicKey = await res.text(); convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey); console.log(`vapidPublicKey: ${vapidPublicKey}`); // (変換した)パブリックキーをapplicationServerKeyに設定してsubscribe subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: convertedVapidKey }); console.log(`subscription : ${JSON.stringify(subscription)}`); // 通知の許可を求める Notification.requestPermission(permission => { console.log(permission); // 'default', 'granted', 'denied' }); } catch (err) { console.log(err); } })(); btnWebPushTest.onclick = async evt => { if (!subscription) return console.log('sbuscription is null'); await fetch('/webpushtest', { method: 'POST', body: JSON.stringify(subscription), headers: { 'Content-Type': 'application/json', }, }); }; 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; }
最後に、Push 通知を受け取る側
sw.js
self.addEventListener('push', evt => { const data = evt.data.json(); console.log(data); const title = data.title; const options = { body: data.body, icon: 'test.jpg' } evt.waitUntil(self.registration.showNotification(title, options)); }); self.addEventListener('notificationclick', evt => { evt.notification.close(); });
起動してみる
node index.js
と叩くとサーバが起動。
にアクセスすると
因みに Chrome の開発者ツールを開いたときにこんなエラーが出ている場合、以前の Push 通知の受信設定が生きてるか何かしてると思われる。
その場合は、開発者ツールの「アプリケーション」タブから削除して画面を開き直そう。
成功するとこんなログが吐き出される。
サーバから「vapid」(中身は公開鍵)を受け取って、自己の識別情報、通知先のデータを生成しているのが解る。
Push 通知を送ってみる。
コレをサーバに送信すると、NodeJS 側でコレが5秒後に応答を返す。
app.post('/webpushtest', (req, res) => { console.log(req.body); try { setTimeout(async _ => { // ちょっと遅延させて通知 await webPush.sendNotification(req.body, JSON.stringify({ title: 'Web Push通知テスト', })); }, 5000); res.json({ success: true }); } catch (err) { console.log(err); } })
サーバ側で受け取った JSON はコレ
{ endpoint: 'https://fcm.googleapis.com/fcm/send/f7iyB(中略)', expirationTime: null, keys: { p256dh: 'BN(中略)', auth: 'hB2f(中略)' } }
fcm.googleapis.com
の FCM は Firebase Clowd Messaging の略らしい。
FCM の仕様はこちらを参照。