serviceworkerでwebpush!
はじめに
プッシュ通知といえばスマホにアプリのインストールして初めて受け取れる(配信できる)もの、というイメージがありますが、
webpushを使うことでアプリをインストールすることなく、通常のPCやスマホのwebブラウザに向けてプッシュ通知を配信することが出来ます。
このwebpushとは独自技術ではなくIETFによって策定され各ブラウザによって実装された、もしくは将来的にされる仕様です。
つまりブラウザさえインストールされていればプッシュ通知を配信することが出来るので、ネイティブアプリによるプッシュ通知と同等以上のリテンションが期待できる可能性があると思います。
webpush
webpushを受け取るためにはservice worker
が必要になります。service worker
とはwebページとは別にブラウザがバックグラウンドで実行するjavascriptで、簡単に言えばネイティブアプリのような機能をwebでも提供する技術です。詳しくは以下を御覧ください。
https://developers.google.com/web/fundamentals/getting-started/primers/service-workers?hl=ja
重要な点としてservice worker
はlocalhostかhttpsのプロトコルでのみ動作します。そのためwebpushもそのどちらかでしか動作しません。
webpushは通常のiOS、androidアプリと同じようにプッシュ配信サーバ(Firebase等)を通して配信されます。詳しい仕組みはこのあたりの記事で。
http://qiita.com/tomoyukilabs/items/217915676603fda73b0a
対応ブラウザはChrome、Firefox、Safari(OS X)です。
実装
仕様等は置いといてRailsでの実装をしてみます。
サーバ側から任意のタイミングでプッシュ通知を送りたいため、ブラウザ毎のプッシュ配信用の情報をDBに保存しておき、特定ユーザに向けてプッシュを送れるようにしてみたいと思います。
DB構成
簡略化のため以下を想定します。
users
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
id | int(11) | NO | PRI | NULL | auto_increment |
devices
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
id | int(11) | NO | PRI | NULL | auto_increment |
user_id | int(11) | NO | MUL | NULL | |
endpoint | varchar(255) | NO | NULL | ||
p256dh | varchar(255) | NO | NULL | ||
auth | varchar(255) | NO | NULL |
gem
実装にあたっては以下のgemを使用します。
https://github.com/zaru/webpush
https://github.com/rossta/serviceworker-rails
VAPIDの生成
インストールしたらプッシュ配信用にpublic_key
とprivate_key
を生成します。
VAPID
については以下。
http://qiita.com/tomoyukilabs/items/9346eb44b5a48b294762#%E5%85%A8%E4%BD%93%E3%81%AE%E6%B5%81%E3%82%8C
生成したpublic_key
とprivate_key
はdotenv-rails
等で環境変数に設定しておきます。
manifest.json
の宣言
次にmanifest.json
を宣言します。詳細な仕様は以下。
https://developer.mozilla.org/en-US/docs/Web/Manifest
上記のmanifest.json
をhtmlのhead
内で読み込みます。
service worker
の登録
service worker
は一つのドメインに対してパス毎に複数登録することができます。それぞれのservice worker
の影響範囲のスコープは登録パスより下のパスに限定されるため、例えば/contents/:id
へのスコープを持ちたければ少なくとも/contents
にインストールする必要があります。今回は/
に一つだけインストールします。
railsのasset pipelineとservice worker
の共存
railsのasset pipeline
ではプリコンパイルされたファイルは/assets/
以下に配置されますが、このままだとservice worker
の上記仕様によりスコープは/assets/
以下になってしまいます。この問題を解決するためにserviceworker-rails
gemを使用します。
rails g serviceworker:install
以下のファイルが作成されます。
– config/initializers/serviceworker.rb
– for configuring your Rails app
– app/assets/javascripts/serviceworker.js.erb
– a blank Service Worker script with some example strategies
– app/assets/javascripts/serviceworker-companion.js
– a snippet of JavaScript necessary to register your Service Worker in the browser
– app/assets/javascripts/manifest.json.erb
– a starter web app manifest pointing to some default app icons provided by the gem
– public/offline.html
– a starter offline page
また、以下のファイルが変更されます。
– Adds a sprockets directive to application.js
to require serviceworker-companion.js
– Adds serviceworker.js
and manifest.json
to the list of compiled assets in config/initializers/assets.rb
– Injects tags into the head of app/views/layouts/application.html.erb
for linking to the web app manifest
service worker
のregister
用コードを記述していきます。
vapid
のpublic_key
をBase64
でデコード。
上記文字列をjavascriptに渡す。
service worker
の登録とプッシュ通知の購読。
これでプッシュ通知の購読が成功すれば/devices
にプッシュ配信用のパラメータがPOSTされます。
このパラメータを保存します。
ちなみにモデルは以下のようにしています。
User
Device
リソースの定義。
コントローラの定義。受け取ったパラメータに変更があれば追加で保存します。ユーザ認証にDevise
を用いています。
プッシュの配信(サーバ側実装)
サーバ側からプッシュの配信リクエストを送ります。色々なところから呼び出す可能性があるのでサービスクラスに実装します。
service worker
スクリプトの実装
service worker
の中身を実装します。今回はwebpushが目的なのでキャッシュ等は考慮しません。
完成
以上で一通り実装できました。rails s
して画面を叩くとservice worker
が登録されるタイミングで以下のようなSQLが発行されてendpoint
等のパラメータが登録されます。
SQL (0.4ms) INSERT INTO `devices` (`user_id`, `endpoint`, `p256dh`, `auth`, `created_at`, `updated_at`) VALUES (1, 'https://fcm.googleapis.com/fcm/send/dliOR...:APA91bEhd...', 'BFJBsocE...', 'gDmTL2...', '2017-05-08 10:49:57', '2017-05-08 10:49:57')
この状態でrails c
でコンソールを起動し以下のコマンドを叩くとwebpushが来てくれるはずです。
WebpushService.new.webpush_clients('hoge')
終わりに
というわけでwebpushを実装してみました。
なんだか長くなってしまいましたが、実際にプッシュ通知を送信する部分と購読する部分の処理は結構簡単なので、重要な情報や非同期な処理の完了などを通知してあげるとシャレオツなんじゃないかと思います。
参考
https://developer.mozilla.org/ja/docs/Web/API/WindowClient
https://tech.drecom.co.jp/introduction-of-the-web-push-notification-system-using-the-service-worker/
https://developer.mozilla.org/en-US/docs/Web/Events/notificationclick
http://qiita.com/tomoyukilabs/items/217915676603fda73b0a
https://rossta.net/blog/using-the-web-push-api-with-vapid.html
http://qiita.com/tomoyukilabs/items/9346eb44b5a48b294762
TAG
基本的にRuby on Railsで開発してます。最近はvue.jsも。好きな塔は円城です。
TAG
- Android
- AWS
- Bitrise
- CodePipeline
- Firebase
- HTML
- iOS
- IoT
- JavaScript
- KPI
- Linux
- Mac
- Memcached
- MGRe
- MGReのゆるガチエンジニアブログ
- MySQL
- PHP
- PICK UP
- PR
- Python
- Ruby
- Ruby on Rails
- SEO
- Swift
- TIPS
- UI/UX
- VirtualBox
- Wantedly
- Windows
- アクセス解析
- イベントレポート
- エンジニアブログ
- ガジェット
- カスタマーサクセス
- サーバ技術
- サービス
- セキュリティ
- セミナー・展示会
- テクノロジー
- デザイン
- プレスリリース
- マーケティング施策
- マネジメント
- ラボ
- リーンスタートアップ
- 企画
- 会社紹介
- 会社紹介資料
- 勉強会
- 実績紹介
- 拡張性
- 採用
- 日常
- 書籍紹介
- 歓迎会
- 社内イベント
- 社員インタビュー
- 社長ブログ
- 視察
- 開発環境