備忘録

備忘録

Push APIを利用してPush通知をする方法

Ⅰ. はじめに

タイトルの通り「Push APIを利用してPush通知をする方法」です。

Ⅱ. 環境

下環境でテストしました

Ⅲ. 手順

1. VAPIDを生成する

以下Webサイト等を利用する

2. クライアント側サンプルプログラムを書く

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="manifest" href="/manifest.json">
  <script src="/service_worker.js"></script>
  <script src="/script.js"></script>
</head>

<body>
  <ul>
    <li><button onclick="subscribePushNotification()">Push通知を許可する</a></li>
    <li><button onclick="unsubscribePushNotification()">Push通知を拒否する</a></li>

    <li>endpoint<input type="text" id="endpoint" readonly></li>
    <li>p256dh<input type="text" id="p256dh" readonly></li>
    <li>auth<input type="text" id="auth" readonly></li>
  </ul>
</body>
</html>

manifest.json

{
  "name": "Push API Test App",
  "display": "standalone"
}

service_worker.js

// プッシュ通知を「受信」した時
self.addEventListener('push', (event) => {
  const obj = JSON.parse(event.data.text())

  const options = {
    body: obj.message,
    icon: '/icon.png',
    id: obj.id,
    actions: [
      { action: 'action001', title: 'title001' },
      { action: 'action002', title: 'title002' }
    ]
  }

  event.waitUntil(self.registration.showNotification(obj.title, options))
})

// プッシュ通知を「クリック」した時
self.addEventListener('notificationclick', (event) => {
  event.notification.close()

  switch (event.action) {
    case 'action001':
      event.waitUntil(clients.openWindow('https://example.com/1'))
      break
    case 'action002':
      event.waitUntil(clients.openWindow('https://example.com/2'))
      break
    default:
      event.waitUntil(clients.openWindow('https://example.com/3'))
      break
  }
})

script.js

window.addEventListener('load', async () => {
  const registration = await navigator.serviceWorker.register('/service_worker.js', { scope: '/' })
  console.log('サービスワーカー登録結果', registration)
})

async function requestNotificationPermission () {
  switch (Notification.permission) {
    case 'default':
      console.log('Push通知が未設定(デフォルト状態)')
      // Push通知権限をリクエストする
      const permission = await Notification.requestPermission()
      return (permission === 'granted')
    case 'denied':
      console.log('Push通知が拒否されている')
      return false
    case 'granted':
      console.log('Push通知が許可されている')
      return true
  }
}

async function subscribePushNotification () {
  if (!await requestNotificationPermission()) {
    return
  }

  const vapidPublicKey = 'YOUR_VAPID_PUBLIC_KEY'

  const registration = await navigator.serviceWorker.getRegistration()
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: vapidPublicKey
  })

  const p256dh = subscription.getKey('p256dh')
  const auth = subscription.getKey('auth')

  document.getElementById('endpoint').value = subscription.endpoint
  document.getElementById('p256dh').value = btoa(String.fromCharCode.apply(null, new Uint8Array(p256dh)))
  document.getElementById('auth').value = btoa(String.fromCharCode.apply(null, new Uint8Array(auth)))
}

async function unsubscribePushNotification () {
  const registration = await navigator.serviceWorker.getRegistration()
  const subscription = await registration.pushManager.getSubscription()

  if (subscription) {
    const result = await subscription.unsubscribe()
    console.log(result)
  }
}

icon.png
https://www.irasutoya.com/2016/07/blog-post_26.html

3. Push通知を送信する為のサンプルプログラムを書く

Program.cs

// dotnet add package WebPush --version 1.0.12
using WebPush;
using Newtonsoft.Json;

var webPushClient = new WebPushClient();

var vapidPublicKey = "YOUR_VAPID_PUBLIC_KEY";
var vapidPrivateKey = "YOUR_VAPID_PRIVATE_KEY";

var endpoint = "https://...";
var p256dh = "...";
var auth = "...";

var subscription = new PushSubscription(endpoint, p256dh, auth);

var data = new Dictionary<string, object?>
{
    ["id"] = Guid.NewGuid().ToString(),
    ["title"] = "hello",
    ["message"] = "あいうえお"
};
var payload = JsonConvert.SerializeObject(data);

var vapidDetails = new VapidDetails("http://example.com", vapidPublicKey, vapidPrivateKey);

await webPushClient.SendNotificationAsync(subscription, payload, vapidDetails);

実行結果

Windows
Windows 通知センター
iOS ホーム画面
iOS ロック画面
Android

FAQ

Q1. 通知されない

以下を確認して下さい

  • 通知の許可がされていない
  • iOSSafariで「ホーム画面に追加」を行っていない
  • OS側の設定で通知がオフに設定されている
  • OS側の設定で「おやすみモード」「集中モード」などが設定されている
  • Webブラウザ拡張機能によって通知がブロックされている
  • Windowsの通知センター内に通知がされている(Winキー + Nで表示可能)
Q2. C#でVAPIDを生成したい
// dotnet add package WebPush --version 1.0.12
using WebPush;

var vapidKeys = VapidHelper.GenerateVapidKeys();
var vapidPublicKey = vapidKeys.PublicKey;
var vapidPrivateKey =  vapidKeys.PrivateKey;