ServiceWorker の WebPush について、調べたことを学習のまとめとして記載します。
過去に実装したことをまとめた記事
前に、django-push-notifications で、WebPush 通知を登録のみ実装しました。
ServiceWorker の WebPush で通知を送るメリット
結構前から、ブラウザ上に通知を送るライブラリ、サービス等はありますが、ServiceWorkerから通知を送るメリットは、自サイトから離れた状態のユーザーにも、通知が送れることです。ブラウザとして全ての画面を閉じても起動さえしていれば、ServiceWorker が稼働しているため、通知を送付することができます。Webサイトと、ユーザーのコミニュケーション手段として、メール、RSS、電話、チャット等ありますが、その選択肢が1つ増えます。
WebPush サービスについて
自前でサーバーを建てるか、SaaSを使うかの選択肢があります。
以下、読んでためになった記事と、github repository へのリンクになります。
-
オープンソース
-
SaaS
個人的に、使用するのであれば OneSignal が今のところ完全に無料なのと、Marketo 等の MA ツールとの連携ができたり、チャネルに対してメッセージを送信するバックオフィス機能があり実用性高そうに思いました。1
WebPush 通知のライフサイクル
WebPsuh 登録から考慮すること
VAPID を使う方式を試しました。
-
WebPushの許可を求める
Web Notifications API を使用して、通知の許可をユーザーに求めます。
末許可の状態で、購読処理を行うと例外が発生します。
許可を求めるタイミングは重要で、ページ読み込み時に表示しているサイト等もありますが、ユーザーの迷惑になる可能性があり、Lighthouse で警告が出力されます。以下、表示タイミングについて書かれた記事へのリンクです。 -
WebPushの購読
self.registration.pushManager.subscribe()
で SerivceWorker 内でサブスクリプションを生成します。 生成したサブスクリプションを加工して、アプリケーションサーバーに送信します。 -
WebPushの送信依頼
アプリケーションサーバー、等 Push サーバーへの送信が可能なサーバからWebPush の送信を Push サーバーへ依頼します。
言語的な縛りは特にないかと思います。個人的にはここは python が担っています。 -
Pushサーバからクライアントへの送信
Pushサーバーからクライアントへメッセージを送信します。
ここは、FCM を使っているためブラックボックスです。 -
クライアントで、メッセージを受信する
ServiceWorker でメッセージを受信します。
実装はなにかを参考にして、以下の実装にしました。
// Push通知 self.addEventListener('push', function(event) { let responseJson; let title; let message; let messageTag; try { // Push is a JSON responseJson = event.data.json(); title = responseJson.title; message = responseJson.message; messageTag = responseJson.tag; } catch (err) { // Push is a simple text title = ''; message = event.data.text(); messageTag = ''; } self.registration.showNotification(getTitle(title), getNotificationOptions(message, messageTag)); // Optional: Comunicating with our js application. Send a signal self.clients.matchAll({includeUncontrolled: true, type: 'window'}).then(function(clients) { clients.forEach(function(client) { client.postMessage({ 'data': messageTag, 'data_title': title, 'data_body': message, }); }); }); });
-
通知の表示
これはブラウザの仕事です。 -
通知のボタンクリック後のアクション
ここも何かのサンプルそのままです。
ServiceWorker でクライアントでメッセージ表示後の ボタンアクションを定義できます。
// 通知クリック時の動作を定義 self.addEventListener('notificationclick', function(event) { // Android doesn't close the notification when you click it // See http://crbug.com/463146 event.notification.close(); // Check if there's already a tab open with this URL. // If yes: focus on the tab. // If no: open a tab with the URL. event.waitUntil(self.clients.matchAll({type: 'window', includeUncontrolled: true}).then(function(windowClients) { for (let i = 0; i < windowClients.length; i++) { let client = windowClients[i]; if ('focus' in client) { return client.focus(); } } }) ); });
登録からの流れは以上です。
WebPush サブスクリプションの期限切れ
サブスクリプション には期限があり期限が切れます。
VAPID で且つ、Chrome の場合、現在期限が切れないようですが、他のブラウザについては切れる可能性があるようです。
サンプルが見つけられず、実際に発生するのか検証できていないので、他のイベントで発生時のFallbackをしつつ、pushsubscriptionchange
が発火した際に、検知できるように GoogleAnalytics で event の送信を行うことを考えましたが、ライブラリは見つけたものの、実装方法がわからずでした。
importScripts('path/to/offline-google-analytics-import.js');
workbox.googleAnalytics.initialize();
self.addEventListener('pushsubscriptionchange', function() {
// Offline GA 送信 をするコード
// 実装しようと思いましたが、実装サンプルがなく実装方法がわかりませんでした。
// オフラインでなければ、postMessage Window側にメッセージを返して、そこからga送信でもいいかもしれません。
});
-
参考情報
-
sw.js
サンプルの実装を見る限り、再発行を行っています。 -
[改訂版] Web Pushでブラウザにプッシュ通知を送ってみる - Qiita
今のところChromeのプッシュ通知(FCM)では特にエンドポイントに有効期限が設けられていないため、常にnullとなります。
Microsoft Edgeでは有効期限が30日間となるようです。 -
pushsubscriptionchange - Web 技術のリファレンス | MDN
参考情報があまり書いていないドキュメントです。 -
Options of a PushSubscription | Web | Google Developers
PushSubscriptionOptions を使って、キーの更新が可能になったという記載です。
-
少なくとも、IEでは期限が切れる可能性があるので、期限切れ更新通知は実装しておいたほうがよさそうに思います。
WebPush サブスクリプションの解除
self.registration.pushManager.unsubscribe()
で SerivceWorker でサブスクリプションの解除が行えます。
正直、WebPush の受け取りますか? は尋ねられるサイトはありますが、購読解除はあまり見かけない気がします。
自分で削除できるので、あまりうざいと思う人は、個人で削除はすると思いますが、マナーとしては実装しておくべきだと思います。
Blogだったら Aboutページとか記事単位で WebPush の解除できたらいいのでしょうか。
作成中のWebpush実装
作りかけですが、随時以下にUPしています。
mezzanine-theme-clean-blog/clean_blog_frontend/src/js at master · kemsakurai/mezzanine-theme-clean-blog
購読しますかは聞きますが、Push サーバーへの送信機能はなく、解除機能はない状態ですね....
以上です。
-
個人の実装は、OneSignal の存在を知らずに、FCM ベースで作成を行いました。切り替えが簡単なのであれば OneSignal に変えてしまおうかと考えています。 ↩
コメント