ウェブサイトとPWAにおけるウェブプッシュ通知の扱い方
プッシュ通知は、現代のウェブで一般的な光景です。これらは、ユーザーがサイトを実際に開いていなくても、タイムリーな情報を伝える手段を提供します。ユーザーのブラウザは、受信したプッシュイベントを処理し、WindowsのアクションセンターやAndroidのロック画面のようなシステムUIを使用して通知を表示します。
サイトまたはPWAにWeb Pushを実装するには、2つの異なるブラウザAPIの組み合わせが必要です。通知の購読と受信を担当するコードは、サービスワーカーのPush APIコンポーネントを使用します。このコードはバックグラウンドで継続的に実行され、新しい通知を処理する必要があるときにブラウザによって呼び出されます。
イベントが受信されると、サービスワーカーは通知を実際に表示するために通知APIを使用する必要があります。これにより、OSレベルのインターフェースを介した視覚的な警告が作成されます。
ここでは、あなたのサイトでWebプッシュを機能させるための完全なガイドを提供します。プッシュ購読を登録し、アラートを送信できるサーバーサイドコンポーネントがすでにあると仮定します。
サービスワーカー
サービスワーカーから始めましょう。サービスワーカーには複数の役割があります。オフラインでの使用のためにデータをキャッシュしたり、定期的なバックグラウンド同期を実行したり、通知ハンドラーとして機能したりします。サービスワーカーはイベント駆動型アーキテクチャを使用します。一度サイトによって登録されると、ユーザーのブラウザは、サービスワーカーがサブスクライブしているイベントが生成されると、バックグラウンドでサービスワーカーを呼び出します。
ウェブプッシュには、1つのコアイベントが必要です。
push. これは受け取ります
PushEventサーバーからプッシュされたペイロードにアクセスするためのオブジェクト。
self.addEventListener("push", e => {
const payload = JSON.parse(e.data.text());
e.waitUntil(self.registration.showNotification(
payload.title,
{
body: payload.body,
icon: "/icon.png"
}
));
});
上記のコードは、受信するプッシュイベントに反応できるサービスワーカーを設定します。サーバーがこのようなJSONペイロードを送信することを期待しています:
{
"title": "Title text for the notification",
"body": "This is the longer text of the notification."
}
プッシュイベントが受信されると、サービスワーカーは次の呼び出しによってブラウザ通知を表示します。
showNotification()その機能は利用可能です
self.registrationプロパティ。関数がラップされています。
waitUntil()
通知が表示されるのをブラウザが待つようにするために、サービスワーカーを終了する前に呼び出してください。
その
showNotification()この関数は2つの引数を受け取ります:通知のタイトルテキストとオプションオブジェクトです。この例では2つのオプションが渡されます:いくつかの長めの本文テキストと通知に表示するアイコンです。振動パターン、カスタムバッジ、対話要件を設定できる多くの他のオプションも利用可能です。すべてのブラウザおよびオペレーティングシステムがAPIによって公開されるすべての機能に対応しているわけではありません。
メインのJavaScriptにサービスワーカーを再登録して、サービスワーカー側のコードを完成させてください:
if (navigator.serviceWorker) {
// replace with the path to your service worker file
navigator.serviceWorker.register("/sw.js").catch(() => {
console.error("Couldn't register the service worker.")
});
}
このコードは各ページの読み込み時に実行される必要があります。これはブラウザがサービスワーカーをサポートしているかを確認し、その後ワーカーファイルを登録します。ブラウザは、サーバーコピーが現在インストールされているバージョンとバイト差異を示すと、自動的にサービスワーカーを更新します。
プッシュ購読の登録
今、ブラウザにプッシュ通知を登録する必要があります。以下のコードは、サービスワーカーの外にあるメインJavaScriptファイルに含めるべきです。
async function subscribeToPush() {
if (navigator.serviceWorker) {
const reg = await navigator.serviceWorker.getRegistration();
if (reg && reg.pushManager) {
const subscription = await reg.pushManager.getSubscription();
if (!subscription) {
const key = await fetch("https://example.com/vapid_key");
const keyData = await key.text();
const sub = await reg.pushManager.subscribe({
applicationServerKey: keyData,
userVisibleOnly: true
});
await fetch("https://example.com/push_subscribe", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
endpoint: sub.endpoint,
expirationTime: sub.expirationTime,
keys: sub.toJSON().keys
})
});
}
}
}
}
次に、ブラウザをプッシュ通知に登録するための関数を呼び出してください:
await subscribeToPush();サブスクリプションコードが何をしているのか見ていきましょう。最初の数行では、サービスワーカーの存在をチェックし、その登録を取得し、プッシュ通知のサポートを検出します。
pushManagerWeb Pushをサポートしていないブラウザでは設定されません。
呼ぶ
pushManager.getSubscription()現在のブラウザのプッシュ購読を記述するオブジェクトに解決するPromiseを返します。これがすでに設定されている場合、ユーザーを再購読させる必要はありません。
本当のサブスクリプションフローは、サーバーのVAPIDキーの取得リクエストから始まります。VAPID仕様は、ブラウザがプッシュイベントが実際にあなたのサーバーから来ていることを確認できるようにするメカニズムです。VAPIDキーを提供するサーバーAPIエンドポイントを公開する必要があります。これは次のように提供されます。
pushManager.subscribe()ブラウザが信頼できるキーを知るための機能です。別々の
userVisibleOnlyオプションは、画面に明示的に表示される通知のみを表示することを示しています。
ザ
pushManager.subscribe()呼び出しは返します a
PushSubscription新しいサブスクリプションを説明するオブジェクト。このデータは別のフェッチリクエストでサーバーに送信されます。実際のアプリでは、アクティブなユーザーのIDも送信し、プッシュサブスクリプションをそのデバイスにリンクできるようにします。
ユーザーにプッシュ通知を送信するためのサーバーサイドコードは、次のようになります:
- ターゲットユーザーにリンクされたすべてのプッシュサブスクリプションをデータストアにクエリします。
各サブスクリプションによって示されたエンドポイントに通知ペイロードを送信し、サブスクリプションの認証キーを含めることを確認してください。
keys
購読時にブラウザから送信されたデータに。その後、ブラウザに送信したのと同じVAPIDキーでイベントに署名してください。
各サブスクリプションの
endpointブラウザベンダーの通知配信プラットフォームを参照します。このURLにはすでにサブスクリプションのユニーク識別子が含まれています。エンドポイントにペイロードを送信すると、ブラウザのバックグラウンドプロセスが最終的にデータを受信し、サービスワーカーを起動します。AndroidのChromeでは、ブラウザプロセスがシステム通知デーモンと直接統合されています。
ユーザーをいつサブスクライブするべきか?
サブスクリプションフローを設定する際は、ユーザーが登録が完了する前にブラウザの権限リクエストの確認をしなければならないことを覚えておいてください。多くのブラウザは、自動的に不要な権限リクエストを隠したり拒否したりします。そのため、ユーザーがあなたのサイトにアクセスした瞬間にサブスクリプションを促すことは、必ずしも望む結果をもたらすとは限りません。
成功にサインアップするための最良の機会は、サブスクリプションリクエストを直接ユーザーのアクションに結びつけることです。通知の有効化の利点を説明し、「今すぐ有効にする」ボタンを提供するアプリ内バナーの提供を検討してください。ユーザーがすでにサブスクライブしているかどうかを確認し、そのバナーを非表示にすることができます。
pushManager.getSubscription()上記の関数。
有効ボタンをクリックすると、サブスクリプション機能が呼び出されるはずです。このプロセスは、ブラウザが登録をセットアップし、ネットワーク呼び出しが完了する間、数秒かかる場合があります。この間、ローディングスピナーを表示することで、ユーザーに状況を知らせるのに役立ちます。
ユーザーには、退会する方法も与えられるべきです。いつでもブラウザの権限を取り消すことができますが、特にサイトをPWAとしてインストールした場合、一部のユーザーはアプリ内のオプションを探すでしょう。
こちらが簡単な解約実装です:
async function unsubscribePush() {
const reg = await navigator.serviceWorker.getRegistration();
const subscription = await reg.pushManager.getSubscription();
if (subscription) {
await subscription.unsubscribe();
await fetch(`https://example.com/push_unsubscribe/${subscription.endpoint}`, {method: "DELETE"});
}
else {
// already subscribed
}
}
呼ぶ
unsubscribe()上で
PushSubscriptionサブスクリプションをキャンセルすると、ブラウザはデフォルトの状態に戻ります。サービスワーカーは受信を停止します
pushイベント。このサブスクリプションのエンドポイントはあなたのサーバーに送信されるため、データストアから削除し、現在は無効になったURLにデータを送信するのを避けることができます。
期限管理と更新手続き
あなたはそのことに気づいたかもしれません。
expirationTime不動産の上に
PushSubscriptionブラウザによって作成されたオブジェクトです。これは常に設定されるわけではありません; 設定されているとき、この時間後にデバイスは通知を受け取り続けるのをやめます。
実際には、
expirationTime現在主要なブラウザでは使用されていません。Chromeによって生成されたトークンは手動でサブスクリプションを解除するまで期限が切れませんので
expirationTime常に
null. Firefoxは設定しません
expirationTimeどちらでも、しかしその通知サービスは、彼らの寿命の間に購読を置き換えることができます。
ブラウザがあなたのアクティブなプッシュサブスクリプションを変更するのに応じて応答することができます。
pushsubscriptionchangeサービスワーカー内のイベントです。残念ながら、このイベントには2つのバージョンがあります:Firefoxで現在使用されている元の実装と、まだどのブラウザでもサポートされていない新しいv2です。
元の仕様には、イベントに応じるのが難しくなる深刻なユーザビリティの問題があります。v1イベントを受信すると、ブラウザは元のサブスクリプションを削除してしまい、新しいサブスクリプションを手動で作成する必要があります。問題は、期限切れのサブスクリプションにアクセスできないため、サーバーに「置き換え」リクエストを送信できないことです。古いサブスクリプションにアクセスする方法がありません。
endpointURL。
v2仕様は、これをイベントを提供することで解決します
oldSubscriptionそして
newSubscriptionプロパティ。イベントを受信すると、古いサブスクリプションはキャンセルされますが、そのプロパティにまだアクセスできます。新しいサブスクリプションはブラウザによって自動的に作成されました。
ここに実装の例があります
pushsubscriptionchange新しい仕様で:
self.addEventListener("pushsubscriptionchange", e => {
e.waitUntil(async () => {
await fetch("https://example.com/push_change", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
auth: (e.newSubscription.toJSON().keys?.auth || null),
endpoint: e.newSubscription.endpoint,
endpointOld: e.oldSubscription.endpoint,
expirationTime: e.newSubscription.expirationTime,
p256dh: (e.newSubscription.toJSON().keys?.p256dh || null)
})
});
});
});
エンドポイントはユニークであるため、サーバーは古いサブスクリプションを照会して、プロパティを新しいサブスクリプションのものに更新できます。古い仕様のサポートも追加したい場合は、プッシュAPIの外部でアクティブなサブスクリプションエンドポイントを手動で追跡する必要があります。それを保存するには
localStorageまたは IndexedDB を使用すると、あなたの中でそれにアクセスできます
pushsubscriptionchangeハンドラーを使用して、サーバーにサブスクリプションを置き換えるように依頼できます。
改訂された仕様は、以前のものよりも実装がはるかに簡単です。ブラウザでまだサポートされていなくても、それをサービスワーカーに追加する価値があります。数行のコードで、新しいブラウザのリリースに対してプッシュ処理を未来に備えさせることができます。
アクションボタンの追加
プッシュ通知には、ユーザーが即座にアクションを取ることができるインタラクティブなボタンが含まれる場合があります。これが
showNotification()作成するコール:
self.registration.showNotification(
"Notification with actions",
{
body: "This notification has a button.",
actions: [
{
action: "/home",
title: "Go to Homescreen",
icon: "/home.png"
}
]
}
);
各通知には、ラベル、アイコン、およびそれぞれ複数のアクションを含めることができます。
action後者のプロパティは、ユーザーの押下に応じてアプリが開始できるアクションを特定する必要があります。
ユーザーがアクションをタップすると、あなたのサービスワーカーが受信します。
notificationclickイベント :
self.addEventListener("notificationclick", e => {
const uri = e.action;
const notification = e.notification;
notification.close();
clients.openWindow(`${self.location.origin}${action}`);
});
私たちは使用しています
actionユーザーが移動できるURIを宣言するためのプロパティ。通知が押されると、新しいタブがそのURIで開かれます。呼び出す
notification.close()通知が消去されることも保証します。そうでなければ、一部のプラットフォームではユーザーが手動でスワイプして消去する必要があります。
要約
Web Pushを実装するのは、関連するAPIを以前に使用したことがないと大変に感じるかもしれません。しかし、技術的な懸念以上に、ユーザーエクスペリエンスを最優先に考え、通知を有効にする価値がある理由をユーザーに伝えることを忘れないようにしましょう。
プッシュの購読と解除は、アプリケーションのメインJavaScriptコード内で行われます。
navigator.serviceWorkerAPI。新しいプッシュイベントに応答し、ブラウザ通知を表示するコードは、サービスワーカー自体に存在します。
ウェブプッシュは現在、ほとんどの主要なウェブブラウザでサポートされていますが、Safariは顕著な例外です。通知は各ブラウザおよびオペレーティングシステムファミリーで異なる表示になるため、特定の機能がそれぞれの環境で同様に動作するとは限らないことを覚えておいてください。
showNotification()APIは普遍的に利用可能になります。



