この Codelab では、プッシュ通知クライアントを段階的に作成する方法について説明します。この Codelab を終了すると、次の機能を備えたクライアントが完成します。
- ユーザーをプッシュ通知に登録します。
- プッシュ メッセージを受信し、通知として表示します。
- ユーザーのプッシュ通知の登録を解除します。
この Codelab は、実践を通して学習することを目的としており、コンセプトについてはあまり説明しません。プッシュ通知のコンセプトについては、プッシュ通知の仕組みをご覧ください。
この Codelab のサーバーコードはすでに完成しています。この Codelab では、クライアントのみを実装します。プッシュ通知サーバーを実装する方法については、Codelab: プッシュ通知サーバーを構築するをご覧ください。
ブラウザの互換性
この Codelab は、次のオペレーティング システムとブラウザの組み合わせで動作することが確認されています。
- Windows: Chrome、Edge
- macOS: Chrome、Firefox
- Android: Chrome、Firefox
この Codelab は、次のオペレーティング システム(またはオペレーティング システムとブラウザの組み合わせ)では動作しないことがわかっています。
- macOS: Brave、Edge、Safari
- iOS
セットアップ
編集可能なコードのコピーを取得する
- [Remix to Edit] をクリックして、プロジェクトを編集可能にします。
認証を設定する
プッシュ通知を機能させるには、認証鍵を使用してサーバーとクライアントを設定する必要があります。理由については、ウェブ プッシュ プロトコル リクエストに署名するをご覧ください。通常、シークレットは次のような .env
ファイルに保存します。
VAPID_PUBLIC_KEY="BKiwTvD9HA…" VAPID_PRIVATE_KEY="4mXG9jBUaU…" VAPID_SUBJECT="mailto:[email protected]"
public/index.js
を開きます。VAPID_PUBLIC_KEY_VALUE_HERE
は、公開鍵の値に置き換えます。
Service Worker を登録する
最終的に、クライアントは通知を受信して表示するために Service Worker を必要とします。サービス ワーカーはできるだけ早く登録することをおすすめします。詳しくは、プッシュされたメッセージを通知として受信して表示するをご覧ください。
// TODO add startup logic here
コメントを次のコードに置き換えます。
// TODO add startup logic here if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.register('./service-worker.js').then(serviceWorkerRegistration => { console.info('Service worker was registered.'); console.info({serviceWorkerRegistration}); }).catch(error => { console.error('An error occurred while registering the service worker.'); console.error(error); }); subscribeButton.disabled = false; } else { console.error('Browser does not support service workers or push messages.'); } subscribeButton.addEventListener('click', subscribeButtonHandler); unsubscribeButton.addEventListener('click', unsubscribeButtonHandler);
- `Ctrl+Shift+J`(Mac の場合は `Command+Option+J`)を押して、デベロッパー ツールを開きます。
- [Console](コンソール)タブをクリックします。コンソールに
Service worker was registered.
というメッセージが記録されます。
プッシュ通知の権限をリクエストする
ページの読み込み時にプッシュ通知を送信する権限をリクエストしないでください。代わりに、プッシュ通知の受信を希望するかどうかをユーザーに尋ねる UI を用意する必要があります。ユーザーが明示的に確認(ボタンのクリックなど)したら、ブラウザからプッシュ通知の権限を取得する正式なプロセスを開始できます。
public/index.js
で、subscribeButtonHandler()
の// TODO
コメントを次のコードに置き換えます。
// TODO // Prevent the user from clicking the subscribe button multiple times. subscribeButton.disabled = true; const result = await Notification.requestPermission(); if (result === 'denied') { console.error('The user explicitly denied the permission request.'); return; } if (result === 'granted') { console.info('The user accepted the permission request.'); }
- アプリのタブに戻り、[Subscribe to push] をクリックします。ブラウザまたはオペレーティング システムから、ウェブサイトによるプッシュ通知の送信を許可するかどうかを尋ねられることがあります。[許可](またはブラウザや OS で使用されている同等のフレーズ)をクリックします。コンソールに、リクエストが承認されたか拒否されたかを示すメッセージが表示されます。
プッシュ通知に登録する
サブスクリプション プロセスでは、ブラウザ ベンダーが制御する プッシュ サービスと呼ばれるウェブ サービスとのやり取りが行われます。プッシュ通知の登録情報を取得したら、サーバーに送信して、サーバーでデータベースに長期保存する必要があります。サブスクリプション プロセスの詳細については、クライアントをプッシュ通知に登録するをご覧ください。
- 次のハイライト表示されたコードを
subscribeButtonHandler()
に追加します。
subscribeButton.disabled = true; const result = await Notification.requestPermission(); if (result === 'denied') { console.error('The user explicitly denied the permission request.'); return; } if (result === 'granted') { console.info('The user accepted the permission request.'); } const registration = await navigator.serviceWorker.getRegistration(); const subscribed = await registration.pushManager.getSubscription(); if (subscribed) { console.info('User is already subscribed.'); notifyMeButton.disabled = false; unsubscribeButton.disabled = false; return; } const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlB64ToUint8Array(VAPID_PUBLIC_KEY) }); notifyMeButton.disabled = false; fetch('/add-subscription', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(subscription) });
userVisibleOnly
オプションは true
である必要があります。ユーザーに表示される通知(サイレント プッシュ)なしでメッセージをプッシュできるようになる可能性はありますが、プライバシー上の懸念から、ブラウザでは現在その機能が許可されていません。
applicationServerKey
値は、base64 文字列を Uint8Array に変換するユーティリティ関数に依存しています。この値は、サーバーとプッシュ サービス間の認証に使用されます。
プッシュ通知の登録を解除する
ユーザーがプッシュ通知を登録した後、ユーザーが気が変わってプッシュ通知の受信を希望しなくなった場合に、登録を解除する方法を UI で提供する必要があります。
unsubscribeButtonHandler()
の// TODO
コメントを次のコードに置き換えます。
// TODO const registration = await navigator.serviceWorker.getRegistration(); const subscription = await registration.pushManager.getSubscription(); fetch('/remove-subscription', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({endpoint: subscription.endpoint}) }); const unsubscribed = await subscription.unsubscribe(); if (unsubscribed) { console.info('Successfully unsubscribed from push notifications.'); unsubscribeButton.disabled = true; subscribeButton.disabled = false; notifyMeButton.disabled = true; }
プッシュ メッセージを受信して通知として表示する
前述のように、サーバーからクライアントにプッシュされたメッセージの受信と表示を処理するには、Service Worker が必要です。詳しくは、プッシュされたメッセージを通知として受信して表示するをご覧ください。
public/service-worker.js
を開き、サービス ワーカーのpush
イベント ハンドラの// TODO
コメントを次のコードに置き換えます。
// TODO let data = event.data.json(); const image = 'logo.png'; const options = { body: data.options.body, icon: image } self.registration.showNotification( data.title, options );
- アプリのタブに戻ります。
- [通知を受け取る] をクリックします。プッシュ通知が届きます。
- アプリタブの URL を別のブラウザ(または別のデバイス)で開き、定期購入のワークフローを完了してから、[Notify all] をクリックしてみてください。登録したすべてのブラウザで同じプッシュ通知が届きます。ブラウザの互換性に戻って、動作することが確認されているブラウザと OS の組み合わせ、または動作しないことが確認されているブラウザと OS の組み合わせの一覧をご覧ください。
通知はさまざまな方法でカスタマイズできます。詳細については、ServiceWorkerRegistration.showNotification()
のパラメータをご覧ください。
ユーザーが通知をクリックしたときに URL を開く
実際には、通知はユーザーを再エンゲージしてサイトにアクセスしてもらうための手段として使用されるでしょう。そのためには、サービス ワーカーをもう少し構成する必要があります。
- サービス ワーカーの
notificationclick
イベント ハンドラにある// TODO
コメントを次のコードに置き換えます。
// TODO event.notification.close(); event.waitUntil(self.clients.openWindow('https://web.dev'));
- アプリのタブに戻り、別の通知を自分に送信して、通知をクリックします。ブラウザで新しいタブが開き、
https://web.dev
が読み込まれます。
次のステップ
ServiceWorkerRegistration.showNotification()
で、通知をカスタマイズするさまざまな方法を確認してください。- プッシュ通知の仕組みについて詳しくは、プッシュ通知の概要をご覧ください。
- サブスクリプションを管理し、ウェブプッシュ プロトコル リクエストを送信するサーバーを構築する方法については、Codelab: プッシュ通知サーバーを構築するをご覧ください。
- 通知ジェネレータを試して、通知をカスタマイズするすべての方法をテストしてください。