Slide 1

Slide 1 text

運営中の個人開発プロダクトに Web Push機能を導入した話 @nerikeshi_k

Slide 2

Slide 2 text

自己紹介 - 名前 - ねりけし(@nerikeshi_k) - 仕事 - フロントエンドエンジニア - 個人開発 - お題箱 https://odaibako.net - bokasitter https://bokasitter.net - monto https://monto.me

Slide 3

Slide 3 text

私について - 名前 - ねりけし(@nerikeshi_k) - 仕事 - フロントエンドエンジニア - 個人開発者 - お題箱 https://odaibako.net - bokasitter https://bokasitter.net - monto https://monto.me

Slide 4

Slide 4 text

お題箱とは

Slide 5

Slide 5 text

お題箱とは - 匿名メッセージの募集フォームを簡単に開設できるサービス - 2017年から運営中 実際の投稿フォーム

Slide 6

Slide 6 text

お題箱にある受け取り通知機能 - お題を受け取ったときに通知が飛ぶ - 「○○」という投稿が届きました、というもの - 通知方法 - Twitter DM - メール

Slide 7

Slide 7 text

お題箱にある受け取り通知機能の問題 ➔ Twitter DMでの通知はTwitter APIの改訂で維持困難 ➔ 今後メールだけになるのは心許ない

Slide 8

Slide 8 text

https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/ 2023.02.16 iOS 16.4にWeb Pushが来るというニュース

Slide 9

Slide 9 text

お題箱にある受け取り通知機能 - お題を受け取ったときに通知が飛ぶ - 「○○」という投稿が届きました、というもの - 通知方法 - Twitter DM - メール - Web Push(追加) ➔ Web Push通知機能の追加 ➔ iOSのためのPWA対応

Slide 10

Slide 10 text

お題箱の PWA対応と Web Push機能追加

Slide 11

Slide 11 text

お題箱のPWA対応 1. manifest.jsonの設置 2. serviceworkerの設置 ➔ HTTPS化はすでに果たされていたので上記2点だけでPWA対応は終わった

Slide 12

Slide 12 text

1. manifest.jsonの設置 左のようなmanifest.jsonを /manifest.jsonから配信開始

Slide 13

Slide 13 text

1. manifest.jsonの設置 - 全ページの内に上のようなリンクタグを追加

Slide 14

Slide 14 text

2. ServiceWorkerの設置 左のようなサービスワーカーを /sw.jsから配信開始 初導入なので機能は下の2点のみ - “push”でNotificationを出す - “notificationclick”でURLを開く

Slide 15

Slide 15 text

2. ServiceWorkerの設置 - 全ページの内にサービスワーカー読み込みスクリプトを追 加

Slide 16

Slide 16 text

お題箱のWeb Push通知対応 1. バックエンド側の実装 a. VAPID認証用の公開鍵を配信する処理 b. ブラウザからのWeb Push購読開始リクエストを受け付ける処理 c. Web Push購読中ユーザーに対してPush通知を送る処理 2. クライアント側の実装 a. ユーザー向け設定画面への通知購読機能の実装

Slide 17

Slide 17 text

- ブラウザでWeb Pushの購読を作成する際、VAPID認証のための公開鍵が必要 - 事前にサーバー側で秘密鍵と公開鍵のペアを作っておき、適当なパスから公 開鍵を配信する - 例えば、/api/webpush/vapid_public_keyからGETで取れるようにしておく 1. バックエンド側の実装 - a. VAPID公開鍵について

Slide 18

Slide 18 text

1. バックエンド側の実装 - b. 購読作成について 1. ブラウザ側でVAPID認証用の公開鍵をサーバーから取得し、 serviceWorker.pushManager.subscribe()メソッドからPushSubscriptionオブ ジェクトを作成する 2. ブラウザは作成したPushSubscriptionオブジェクトをバックエンドに送る 3. バックエンドは受け取ったPushSubscriptionオブジェクトを送信ユーザーと 紐づけて保存する a. 例えば /api/webpush/subscriptionsにPOSTで作成できるようにする PushSubscriptionオブジェクト: https://developer.mozilla.org/ja/docs/Web/API/PushSubscription

Slide 19

Slide 19 text

1. バックエンド側の実装 - b. 購読作成について - クライアントからバックエンドにPushSubscriptionオブジェクトを送るコー ドはざっくりこのような感じ

Slide 20

Slide 20 text

1. バックエンド側の実装 - c. 通知の送信について - クライアントに送ってもらったPushSubscriptionオブジェクトに含まれる endpointに対して所定の形式でPOSTリクエストを送る - 認証やメッセージ暗号化の詳細については本発表では省略 - お題箱ではRedisにキューを積み、cronで送信ジョブを回している

Slide 21

Slide 21 text

2. クライアントの実装 - a.購読機能の追加 - バックエンド側の実装がすべて済んだらプッシュ通知設定を追加した

Slide 22

Slide 22 text

2. クライアントの実装 - a.購読機能の追加 - ユーザーのブラウザが以下の要素を利用可能な環境かどうか判定する - Service Worker - Push API - Notification API - Notification APIを使って通知許可をユーザーから得る - Push APIを使ってSubscriptionを作り、バックエンドに送る - Subscription作成時、バックエンドからVAPID認証用公開鍵をもらっておいて使う ❖ PWA化している環境向けに特別なにか違うことをする必要はない

Slide 23

Slide 23 text

実装でハマりそうな点 - Web Push送信の失敗はデバッグが難しい - プッシュサーバから成功(201)が返ってきたのにブラウザにプッシュ通知が届かない - あるブラウザへは送信できたのに別のブラウザへは送信できない ➔ 既存のライブラリ実装やOSSのissue, PRを参考にする ➔ SaaSを導入する ➔ 動作検証は対応予定ブラウザ全てで一通りやる

Slide 24

Slide 24 text

実装でハマりそうな点 - ブラウザが現在Web Push購読中か確認する処理がややこしい - navigator.serviceWorker.readyがアクティブなサービスワーカーを返すまでawait - serviceWorker.pushManager.getSubscription()がPushSubscriptionを返すまでawait - PushSubscriptionが得られたらバックエンドに対応するレコードが存在するか問い合わせる - 問い合わせキーにはendpointを使うのがベターそう - バックエンドにレコードがあればWeb Push購読中 - なかったときはブラウザが持っているPushSubscriptionを削除 - … ➔ 一つ一つ段階を追って実装していくのが重要そう

Slide 25

Slide 25 text

実装でハマりそうな点 - ブラウザでの通知許可リクエストの呼び方 - Notification.requestPermission()のこと - 他の環境ではいつ呼んでも「通知を許可する」のダイアログを出せるが、iOSではクリックな どのユーザーの能動的なアクション起因で発火させないと失敗する ➔ UX的にも全ての環境でクリック起因発火するように書くor書き換える

Slide 26

Slide 26 text

おわりに

Slide 27

Slide 27 text

おわりに - Web Push対応は大変だったが勉強になった - 認証や暗号化など、フロントエンドで普段あまり触らない部分に触れることができた - 今後はユーザーにPWA化&Web Pushをもっと使ってもらうための導線設計を したい

Slide 28

Slide 28 text

おわりに - 実装内容をもう少し詳細に書いた記事 - https://zenn.dev/neriko/articles/2e0cde5f93ea95