整合 web push notification 與使用者互動
最近開發了一個應用服務叫 idar,目的是利用 Google Calendar 來當作記帳工具,使用者可以在日曆上紀錄消費,我在後端監看日曆事件,然後在日曆上幫使用者建立統計的事件,讓使用者可以知道今天或是這個月總共花了多少錢。
為了增加便利性,我設計了讓使用者可以輸入電子發票資訊,由後端查詢明細後,自動建立消費紀錄並通知使用者,以及預算超支通知,原本是使用透過 Calendar API ,在日曆上建立一個帶彈出提醒視窗的事件來做通知,不過這樣會讓日曆看起來很亂,而且使用者之後還需要手動刪除。後來想到可以使用 web push message 來對使用者進行通知,經過一番測試後順利整合上去了,現在把實做的過程簡單做個紀錄。
下面是web push 運作大致的流程圖:
對我們而言,需要完成的有三個部份:
- service_worker.js
- register.js
- push service
分別介紹功能與程式碼如下
Service Worker
Service worker 是一種特殊的 javascript,背景執行在瀏覽器中,即使原本的網頁已經關閉也沒關係。而它的任務非常簡單,程式碼也很單純,就是執行的時候呼叫 addEventListener 註冊接收 “push”,在收到訊息時呼叫 showNotification() 顯示通知,詳細的選項可以參考Notification API 的說明。
另外註冊 “notificationclick” 來處理後續使用者的點擊行為,如果沒有特別要處理的就呼叫 self.notification.close() 直接關閉通知即可。
要留意 service_worker.js 這個檔案的位置,建議是放在網站的公開目錄的根目錄下,我有遇到即使是路徑正確,但放在別的目錄下卻無法找到的問題。
service worker 如果有改版,瀏覽器中的版本並不會馬上更新成新版,而是讓新版本進入 pending 狀態,要關閉該網頁後才會更新,或是從開發者模式中強制關閉舊版,測試的時候要注意版本的問題。
register.js
這是網頁上負責管理 web push 的 javascript,是從 Google 的 sample code 修改簡化並移除 UI 部份的程式碼,這樣會比較容易理解它的運作邏輯。
首先在將 service worker 常駐到瀏覽器。
如果註冊 service worker 沒有問題,接著呼叫 initialiseState()檢查目前的訂閱狀態,當然在檢查之前還要先確認一下瀏覽器的支援情形。
訂閱部份也很直覺,呼叫 subscribe() 函數,applicationServerKey 需要指定 VAPID 格式的 public key,這個金鑰組可以從 Firebase 的主控台上產生,因為是標準,所以同樣的金鑰組也可用於 Firefox 瀏覽器上。
取得的訂閱資料的格式如下,endpoint 包含了推播服務的 url 以及 id,而 auth 與 p256dh 則是認證用的資料,將這些資訊上傳到後端 server 儲存到資料庫中,後續推播的時候將會用到。
Push Service
這裡的 push service 是執行在自己的後端 server,主要是提供其他模組進行推播,這裡使用 web-push 這個 module 來幫忙處理與推播服務間的溝通,安裝指令如下:
npm install web-push --save
程式的部份也很簡單,需要推播到特定使用者的瀏覽器上,只要先查詢之前儲存的訂閱資訊,代入到相關資料結構中,最後呼叫 sendNotification() 即可。
web push 的訂閱是根據每個瀏覽器各自獨立的,因此如果想要同時推播給某個使用者的所有裝置時,要把這些不同的訂閱資料透過其他的唯一識別資料連結在一起,例如像 email 或是自訂的 UUID。
web push 整合過程不算困難,只是它的功能有點分散,需要註冊時使用的 javascript,執行在瀏覽器裡的 service worker,自己 server 的後端程式以及各個瀏覽器提供的推播服務,一開始會有點不確定它是怎麼運作的,不過實際上操作過一次就覺得蠻容易了。