Codelab: プッシュ通知クライアントを作成する

Kate Jeffreys
Kate Jeffreys
Kayce Basques
Kayce Basques

この Codelab では、プッシュ通知クライアントを作成する方法をステップごとに説明します。この Codelab を完了すると、次のことができるクライアントが作成されます。

  • ユーザーをプッシュ通知に登録します。
  • プッシュ メッセージを受信し、通知として表示します。
  • ユーザーのプッシュ通知の登録を解除します。

この Codelab は、実践を通じて学習することに重点を置いており、コンセプトについてはあまり説明しません。プッシュ通知のコンセプトについては、プッシュの仕組みをご覧ください。

この Codelab のサーバーコードはすでに完成しています。この Codelab では、クライアントのみを実装します。プッシュ通知サーバーを実装する方法については、Codelab: プッシュ通知サーバーを構築するをご覧ください。

ブラウザの互換性

この Codelab は、次のオペレーティング システムとブラウザの組み合わせで動作することが確認されています。

  • Windows: Chrome、Edge
  • macOS: Chrome、Firefox
  • Android: Chrome、Firefox

この Codelab は、次のオペレーティング システム(またはオペレーティング システムとブラウザの組み合わせ)では動作しないことが確認されています。

  • macOS: Brave、Edge、Safari
  • iOS

セットアップ

認証を設定する

プッシュ通知を機能させるには、認証鍵を使用してサーバーとクライアントを設定する必要があります。理由については、ウェブ push プロトコル リクエストに署名するをご覧ください。通常、シークレットは次のような .env ファイルに保存します。

VAPID_PUBLIC_KEY="BKiwTvD9HA…"
VAPID_PRIVATE_KEY="4mXG9jBUaU…"
VAPID_SUBJECT="mailto:test@test.test"
  1. public/index.js を開きます。
  2. VAPID_PUBLIC_KEY_VALUE_HERE は、公開鍵の値に置き換えます。

サービス ワーカーを登録する

クライアントが通知を受信して表示するには、サービス ワーカーが必要です。サービス ワーカーはできるだけ早く登録することをおすすめします。詳しくは、プッシュされたメッセージを通知として受信して表示するをご覧ください。

  1. // 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);
    
  2. Chrome で DevTools コンソールを開きます。

  3. コンソールに Service worker was registered. というメッセージが記録されます。

プッシュ通知の通知権限をリクエストする

ページ読み込み時にプッシュ通知を送信する権限をリクエストしないでください。代わりに、プッシュ通知を受け取るかどうかをユーザーに尋ねる UI を用意する必要があります。ユーザーが明示的に確認(ボタンのクリックなど)したら、ブラウザからプッシュ通知の通知権限を取得する正式なプロセスを開始できます。

  1. public/index.js で、subscribeButtonHandler() の // 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.');
    }
    
  2. アプリのタブに戻り、[Subscribe to push] をクリックします。ブラウザまたはオペレーティング システムから、ウェブサイトによるプッシュ通知の送信を許可するかどうかを尋ねられます。

  3. [許可](またはブラウザやオペレーティング システムで使用されている同等のフレーズ)を選択します。コンソールに、リクエストが承認されたか拒否されたかを示すメッセージが表示されます。

プッシュ通知に登録する

サブスクリプション プロセスでは、ブラウザ ベンダーが管理するウェブサービス(プッシュ サービス)とやり取りします。プッシュ通知のサブスクリプション情報を取得したら、それをサーバーに送信し、サーバーがデータベースに長期的に保存する必要があります。

  1. 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 コメントを次のコードに置き換えます。
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;
}

プッシュ メッセージを受信して通知として表示する

前述のように、サーバーからクライアントにプッシュされたメッセージの受信と表示を処理するには、サービス ワーカーが必要です。詳細については、プッシュされたメッセージを通知として受信して表示するをご覧ください。

  1. public/service-worker.js を開き、サービス ワーカーの push イベント ハンドラ内の // TODO コメントを次のコードに置き換えます。

    let data = event.data.json();
    const image = 'logo.png';
    const options = {
      body: data.options.body,
      icon: image
    }
    self.registration.showNotification(
      data.title,
      options
    );
    
  2. アプリのタブに戻ります。

  3. [通知を受け取る] をクリックします。プッシュ通知が届きます。

  4. サポートされている他のブラウザでアプリタブの URL を開きます。定期購入ワークフローに沿って操作し、[すべてに通知] をクリックします。それぞれに同じプッシュ通知が届きます。

通知はさまざまな方法でカスタマイズできます。詳細については、ServiceWorkerRegistration.showNotification() のパラメータをご覧ください。

ユーザーが通知をクリックしたときに URL を開く

実際のアプリでは、通知を使用してユーザーを再エンゲージし、サイトにアクセスするよう促すことができます。そのためには、サービス ワーカーをもう少し構成する必要があります。

  1. サービス ワーカーの notificationclick イベント ハンドラ内の // TODO コメントを次のコードに置き換えます。

    event.notification.close();
    event.waitUntil(self.clients.openWindow('https://web.dev'));
    
  2. アプリのタブに戻り、別の通知を自分に送信して、その通知をクリックします。ブラウザで新しいタブが開き、https://web.dev が読み込まれます。

次のステップ