knowledge base

マークアップ/フロントエンドエンジニアのWEB制作における備忘録です。平日はWEB屋、休日は社会人劇団の主宰・劇作家をしています。

【PWA】シリーズPWA (10) クライアントからAPIにリクエストを送って通知を受け取る

クライアント側の実装

クライアント側は、基本的に前回までで実装したAPIを叩きにいくように変更します。

サブスクリプション の登録(と古いものがあれば削除)

前回の実装では、サブスクリプションの情報をconsoleに出力するだけでしたが、実際にサブスクリプションの情報をリクエストヘッダーに乗せてAPIを叩きます。

まずmain.jsにおいてこのようになっていた箇所を、

navigator.serviceWorker.ready.then(function(registration) {
	return registration.pushManager.getSubscription().then(function(subscription) {
		if (subscription) return subscription;
		return registration.pushManager.subscribe({
			userVisibleOnly: true,
			applicationServerKey: convertedVapidKey
		}).then(function (subscription) {
			 var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
			 var key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
			 var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
			 var auth = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
			 var endpoint = subscription.endpoint;
			 console.log(key);
			 console.log(auth);
			 console.log(endpoint);
		});
	})
});

このように書き換えます。

var sendSubscription = function(subscription){
	var data = {};
	var latestID = localStorage.getItem('latestID');
	var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
	data.key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
	var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
	data.auth = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
	data.endpoint = subscription.endpoint;
	data.registrationID = data.endpoint.substring(data.endpoint.lastIndexOf('/')+1, data.endpoint.length);
	localStorage.setItem('latestID', data.registrationID);

	// 新しいサブスクリプションを通知対象に登録する
	fetch('https://*******/add',{
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		mode: 'cors',
		body: JSON.stringify(data)
	})
	.then(function(response) { return response.text(); })
	.then(function(res){ console.log(res); });

	// 古いサブスクリプションがあれば通知対象から削除する
	if (latestID) {
		fetch('https://*******/delete',{
			method: 'POST',
			headers: {
				'Content-Type': 'application/json'
			},
			mode: 'cors',
			body: JSON.stringify({ registrationID: latestID})
		})
		.then(function(response) { return response.text(); })
		.then(function(res){ console.log(res); });
	}
}

navigator.serviceWorker.ready.then(function(registration) {
	return registration.pushManager.getSubscription().then(function(subscription) {
		if (subscription) return subscription;
		return registration.pushManager.subscribe({
			userVisibleOnly: true,
			applicationServerKey: convertedVapidKey
		}).then(function (subscription) {
			sendSubscription(subscription);
		});
	})
});

サブスクリプションの情報をJSON形式にしてリクエストヘッダーに持たせています。

また、最新のregistrationIDを常にlocalStorageで管理し、古いものがあれば(つまりlocalStorageに格納されたregistrationIDがあれば)そのIDは削除するようAPIを叩いています。

push用ページを作成する

pushについては任意の通知内容を設定できるように専用のフォームページを作成し、そのフォームがsubmitされたタイミングで、pushするためのAPIを叩きに行くようにします。 仮にファイル名をpush.htmlとします。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="POST" id="form">
	Title <input type="text" name="title">
	Message <input type="text" name="message">
	<button type="submit">Push</button>
</form>
<script>
document.querySelector('#form').addEventListener('submit', function(e){
	e.preventDefault();
	var title = document.querySelector('#form').querySelector('[name="title"]').value;
	var message = document.querySelector('#form').querySelector('[name="message"]').value;
	var data = { title: title, message: message };
	fetch('https://******/push',{
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		mode: 'cors',
		body: JSON.stringify(data)
	})
	.then(function(response) {
		return response.text();
	})
	.then(function(res){
		console.log(res)
	})
}, false)
</script>
</body>
</html>

push.htmlにアクセスし、テキストフィールドに任意の値を入力してボタンを押せば、入力した内容で通知が送られてくるはずです。