サーバーレスな通知の仕組み
この記事は後日公開予定の「ドアロック通知の仕組みづくり」に関する基礎技術の解説です。
ドアロック通知の仕組みを作るために「通知」を利用したいのですが、それをサーバーレスに実現可能であることの解説を試みます。
ドアロック通知システム構成
- センサデバイス(BLEマイコン+加速度センサ)
- ラスベリーパイ(中継用)
- ブラウザベンダーが用意しているWebPushサーバーを利用
- スマホまたはPCのブラウザ用PWAアプリケーション実装
本記事では後者2点を主に解説します。
WebPush通知とは
従来のPush通知ではスマホアプリの作成が必須であったり、PC専用の常駐型アプリケーションを必要としたり、環境ごとに異なる対応が必要でした。 WebPushの仕組みはブラウザの標準APIとして規定され、環境やブラウザの種別に寄らず一定の手順でPush通知を行えるようになりました。 長らく最後の砦、iOSだけこの対応が実装されないままの期間が長かったのですが、iOS16.4にてついに対応が実装されました。 これで、ほとんどの環境におけるデフォルトインストールされたブラウザにてWebPush通知機能が利用可能になりました。
WebPush通知の全体の流れ
予めVAPIDという鍵を生成しておきます。
このうち公開鍵をブラウザのPWAアプリケーション上に持ってきてPush通知の購読手続きを実行します。
そうするとそのブラウザ専用のPush通知代行サーバーにVAPIDが登録されブラウザ専用のWebPushトークンを受け取ります。 このトークンをPush通知の起点であるラズパイ実装側に保存しておきます。
WebPushトークンとVAPID秘密鍵を使ってブラウザ専用のPush通知代行サーバーに通知したい任意の情報の通知を要求すると、購読手続きをしたブラウザにプッシュ通知が届きます。WebPushトークンにはブラウザ専用のPush通知代行サーバーへのエンドポイント情報も含んでいます。
同じ手順を通知を受けたい複数のデバイスのブラウザでトークンの取得を繰り返してラズパイ実装側に保存して起き、通知するときに複数のトークンを順次使ってそれぞれのブラウザ専用のPush通知代行サーバーにプッシュ通知要求を投げることで同じ通知内容を複数の端末に届けることができます。
以上の挙動により、サーバーレスで通知を送ることができます。
アプリとツール
前述の手続きをより容易に実行できるようにPWAアプリとコマンドラインツールを作成しました。
PWAアプリ: https://github.com/SWITCHSCIENCE/notify-app
GitHub - SWITCHSCIENCE/notify-app: PWA for WebPushPWA for WebPush. Contribute to SWITCHSCIENCE/notify-app development by creating an account on GitHub.
https://github.com/SWITCHSCIENCE/notify-app
コマンドラインツール: https://github.com/SWITCHSCIENCE/notify-tool
GitHub - SWITCHSCIENCE/notify-toolContribute to SWITCHSCIENCE/notify-tool development by creating an account on GitHub.
https://github.com/SWITCHSCIENCE/notify-tool
コマンドラインツールのインストール
- go v1.22 以降が必要です。
go install github.com/SWITCHSCIENCE/notify-tool@latest
- GOPATH/binがPATH環境変数に設定されている必要があります。
初期化(VAPID鍵生成)
ここの手順は一度だけ実行してください。 (重ねて実行するとそれ以前のPush通知先には届かなくなります)
Windows:
notify-tool.exe init
MacOS:
notify-tool init
購読手続き
Windows:
notify-tool.exe subscribe
<QRコード>
main.go:100: open: https://pages.switch-science.com/notify-app/?pubKey=####
subscription:>
MacOS:
notify-tool subscribe
<QRコード>
main.go:100: open: https://switchscience.github.io/notify-app/?pubKey=####
subscription:>
QRコードをスマホで開くか、 main.go:100: open:
以降に書かれたURLを開きます。
iPhoneだけはここでちょっと追加作業が必要です。いったんこの画面を共有ボタンから「ホーム画面に追加(Add to Home)」して、ホーム画面アイコンから開きなおします。
Subscribeボタンをクリックすると、初回は「通知許可確認ダイアログ」が出ますので許可するように操作してください。その後、購読手続きが正常に行われた場合にトークンが表示されます。それをCopyボタンでクリップボードに保存します。この内容を何とかしてPC側に持ち込んでください(メールやクリップボード共有、AirDropなど)。
先ほどのターミナルに戻って、「subscription:>」のプロンプトにて貼り付けしてENTERキーを押します。
これでnotify-toolの管理下にトークンが保存されます。
通知の送信
Windows:
notify-tool.exe push もしもーし!
MacOS:
notify-tool push もしもーし!
以上のコマンドにより以下のような通知が届きます。
Windows:
iPhone:
notify-tool push
のコマンドライン引数の書式は以下の通り。
notify-tool push -title "タイトル" -data `{...json...}` メッセージボディ
dataにはJSONオブジェクトを渡すことができますが、その解釈はPWAアプリのservice-worker.js側の実装次第です。
https://github.com/SWITCHSCIENCE/notify-app/blob/main/static/service-worker.js
ここの「push」イベントハンドラ内容を参考に。 また、通知をクリックしたときの挙動を「notificationclick」イベントハンドラにて記述することもできます。
苦労したところや細かい注意点
- ターミナルー>PWAアプリではURLパラメータにてパブリックキーを渡す。
- PWAアプリー>ターミナルでは購読トークンをクリップボード経由で渡す。
- PWAアプリのサービスワーカーはドメインごとに一つのインストールが基本らしいので、複数のPWAアプリを提供したい場合はサブドメインで分けるほうが無難
- サブフォルダにマニフェストファイルを置く場合、ブラウザでAppをインストールした場合に意図したサービスワーカーが動いてくれない場合があった(つまりiOSでPWAインストール必須でそれ以外ではPWAインストールしないようにする必要があります。)
- 通知要求の応答に失効したエラーが返る場合、管理下にあるトークンは失効済みフォルダに移動して次回からは通知には使いません。
- 管理下にあるトークンの一覧は`notify-tool list`にて確認できます。
まとめ
- サーバーレスにてPush通知の仕組みを作ることができました。
- セキュアに関連付けするのに必要なやり取りを通知が欲しい端末を実際に操作してトークンの交換を行うようにしてみました。
- この場合、第三者に通知を奪われたり知らない通知を発行されたりといったことが発生しにくくなっています。
- このあたりを便利にサクサク関連付けするようにユーザー認証や機器認証の仕組みを実装する場合は、注意して設計しないとセキュリティホールになりやすいので注意が必要です。
- iOSだけはPWAアプリを事前に「ホーム画面に追加(AddToHome)」する必要があります。
- この仕掛けはブラウザのバックグラウンドサービスで動作するのでブラウザを起動しているか否かに関係なく動作します。
- 次回、この仕掛けを使って実際にドアロック通知の仕組みを解説していきます。