本篇大綱
用到的資源
web push 推播功能,這陣子很常看到的一個功能,如果一進入網站,看到網站要求顯示通知的權限,就代表這個網站有用這功能:

那通常,很多網站UX設計不良,在使用者根本就還搞不清楚這網站是幹麻的情況下就跳通知,所以大部份都直接按封鎖了吧XD?
總之,在踩了幾個坑以後,終於完整的寫出了web push的功能。
完整是指會在桌機、安卓手機發出推播通知,並且點了會進到指定的頁面,同時在firebase儲存發送訊息的記錄。
本篇用到的資源如下:
資料庫:firebase realtime database
推播功能:firebase cloud messaging
js framework:Vue.js
web push是PWA一個很重要的功能,關於PWA,可以先參考之前寫的文章:
PWA學習筆記-1:cache、workbox基本使用
PWA學習筆記-2:workbox CLI
PWA學習筆記-3:workbox 參數
PWA學習筆記-4:manifest.json
下面幾段步驟會用到前3篇筆記的東西,就不再另外解釋。
取得FCM金鑰
本篇是用firebase的cloud messaging功能(以下稱FCM),去實作web push。所以第一步是要先在firebase上開一個專案。
以下截圖所用到的firebase專案之後會刪掉,各種金鑰最後都不會存在,純示範用。
這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝
開完專案後,要取得推播金鑰,有了金鑰才能始用FCM的功能。
首先進到firebase後台,點選齒輪後,再點選專案設定:

點擊Cloud Messaging:

頁面往下拉,會看到一個「網路設定」的區塊,有一個「產生金鑰組」的按金,按下去:

就會產生一組web push用的金鑰,先存下來,firebase config裡會用到:

新增manifest.json、firebase config
manifest.json
取得金鑰後,第二步就是新增一個manifest.json的檔案,檔案內容大概如下:
最重要的是這一行:
"gcm_sender_id": "103953800507"
這行一定要有,key、value是固定的,copy貼上就行。
firebase config
建立一個首頁的檔案index.html,在頁尾的部份引用firebase config。
這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝
firebase config一樣是後台有提供,點小齒輪,再點專案設定後,接著點代表web的那個按鈕:

就會出現config了:

copy以後貼到index.html,另外也一併貼上FCM的引用,整合後如下:
最後一行的:
messaging.usePublicVapidKey('XXXXXXXXXXXXXXXXXXXX');
XXX 就是要替換成第一步拿到的FCM金鑰。
取得使用者的token
簡單來說,web push 推播功能的流程如下:
- 註冊service-worker → 向使用者要求允許通知權限 →
- FCM產生這個裝置的token → token寫進資料庫 →
- 從後台使用web push → server發web push到裝置上 →
- 裝置上的service worker接收 → service worker執行notification
token是每一個裝置會有的,之所以會以裝置為單位,而不是以使用者為單位,是因為每一個裝置都可以註冊service worker,而且每次存的token都會不同,所以一個使用者在桌機的chrome、fireox,或是安卓手機的chrome、firefox,都有不同的token。
假設王小明在桌機的chrome、firefox,都按下了允許通知,在安卓手機的chrome、firefox也按了允許通知,那當我們按下發送推播後,王小明就會在4個地方收到相同的通知。因為是用裝置來區分的。
IOS目前還不支援web push。
2020.04.10更新:
今天看到iZooto的一篇文章上寫,在比對了一下caniuse中的service workers支援情況,可以看到IOS11.3開始支援Service Workers了~但web push的功能只支援在mac,尚未支援到iphone上。
新增sw.js
用workbox新增一個sw.js檔案,把firebase的config放進去,程式碼如下:
如果推播裡要放公司的logo,那logo的圖檔就要寫進快取檔案的清單裡,到時推播才有圖檔可以顯示。
註冊sw.js、存cookies、存firebase
如果拿到的token不存在cookies裡,用cookies判斷是否拿過token,那使用者就會存到2組以上的token,在發推播時,就會收到相同的訊息多次。
當然,如果使用者清除了快取,就會有別種情況發生,最好的方式還是讓使用者登入會員後,再取得token,把token跟會員綁一起,就不會有奇奇怪怪的情形出現。
以下為js code:
裡面有一行很重要:
messaging.useServiceWorker(xxx);
這是這次踩到的坑。
如果沒寫這行,就會發現網站存了2個service worker,分別是firebase的,以及我們自己的。這行可以讓FCM只存我們註冊的sw.js,才可以在用FCM推播時,順利的執行推播及點擊後開啟指定的頁面。
成功的話,開啟index.html,在開發人員工具的Application → Service Workers,就會看見註冊了sw.js檔案:

註冊sw.js只能在https下,因此網域必須有SSL,不然會註冊失敗。
messaging.requestPermission()
這行會跟使用者要允許通知,使用者按下允許後,
messaging.getToken()
這行就會產生FCM的token,之後就是存進firebase跟cookies。
firebase上會看到以下:

之後只要跑個迴圈,就可以一個個去發送web push。
發送web push
這邊新增一個admin.html來當做發送web push的後台介面,直接用vue.js抓每個input的值。

web push如果要判斷成效,直接用google analytics的utm參數就可以了,所以後台欄位有給utm用的3個主要參數。
不含樣式的原始碼文末會附上github網址。
在發送web push時,還要填入伺服器的金鑰,這也是從firebase後台可以拿到。點小齒輪 → 專案設定 → Cloud Messaging,第一個「伺服器金鑰」的值就是了:

發送web push的js如下,寫在admin.html裡:
接收web push
接受web push有2種情況:
- 使用者正開啟官網頁面
- 使用者沒有開啟官網頁面
第一種情況,是在index.js下寫一個messaging.onMessage的function處理。
第二種情況,是在sw.js下寫一個messaging.setBackgroundMessageHandler的function處理。
使用者正開啟官網頁面
官網正開啟的狀況下,屬於js的notification功能,function範例如下:
payload就是傳來的值,點擊後要導到的頁面就用location.href來處理。
使用者沒有開啟官網頁面
使用者在上網,但沒有開啟官網的頁面,就是由之前註冊的sw.js處理,在sw.js加入以下:
click_action是點擊後要開啟的頁面網址,但要另外寫一個notificationclick來處理。
這邊踩了一個坑,如果按照一般順序來寫,會先寫了messaging.setBackgroundMessageHandler後,再寫notificationclick。然後就會發現,chrome上可以正常運作,但在firefox上怎麼點就是不會開啟頁面。
google了很久,才看到這篇:service worker notificationclick event doesn’t focus or open my website in tab
click_action是chrome用的,如果messaging.setBackgroundMessageHandler先寫了,那FCM就會全部接收web push的功能,就不會讓原生的notificationclick事件被運作,因此notificationclick得寫在前,讓原生事件運作後,再執行FCM的事件。
補充資源
有了發送、接收,基本上web push就可以順利運作了。
要注意的是web push只接受在https以下運行。
最後附上學習時參考的教學文,以及本篇的Github原始碼。
從建firebase就開始教學的(英文):Tutorial: Web Push notification using Firebase
建立 Service Worker Web Push Notification — (Firebase Push Notification實作紀錄)
Push Notification之成為訂閱用戶(Firebase實作)
Google官方教學的原始碼:Github
Google官方教學的功能示範:Notification Examples
PWA學習筆記系列
- PWA學習筆記-1:cache、workbox基本使用
- PWA學習筆記-2:workbox CLI
- PWA學習筆記-3:workbox 參數
- PWA學習筆記-4:manifest.json
- PWA學習筆記-5:用firebase做web push


請問若使用虛擬主機,是否也可以實現此文章的推播功能(因無法在主機上安裝任何程式),感謝回覆。
主要能夠在頁面上加入程式碼。
如果可以埋google tag manager也行,程式碼也可以寫在裡面。
畢竟還是需要用程式碼去跟使用者要允許推播的權限,跟存token…等等的動作。
用 firebase deploy 指令把程式上傳就可以了。虛擬主機沒有https功能無法做pwa驗證。還有Vue也可以上傳在虛擬主機使用。Node無法在虛擬主機使用,但是Firebase可以做Node的Host主機
請問如果使用者關閉瀏覽器是否也可以收到推撥通知?
無法喔,使用者必需打開瀏覽器才收得到web push。
但他的好處就是,只要打開瀏覽器,使用者即便沒進到你的網站,也能收到推播。
我很懷疑瀏覽器關掉無法推播,因為這不是PWA的精神,PWA是斷網也能看以前看過的。我看代碼都有對Firebase註冊過,所以在瀏覽器關著時,應該能推播。只是我試不出作者的功能,所以關瀏覽器試推播更無法驗證了。希望作者給個網址讓我們試試。或者給個確定沒問題的程式(firebaseConfig當然要放我們自己的)。啊如果真的關瀏覽器無法推播我也懶得再研究了,直接用原生iOS跟Android做了(這個我已經做了,只是不甘心被Apple綁架,想用PWA脫離它的魔掌)
作者在medium.com發布的跟這篇不太一樣,這篇日期比較新,可是沒有留下Github原始碼。medium.com的原始碼一直做不出來,直到把index.html的script部分全部殺掉才沒發現錯誤輸出,但是仍然無法做到推播。如果作者把原始碼更新一下最好。還有請作者把它掛在Firebase的Host,這樣我們都可以直接使用在您的firebaseConfig下實驗推播功能(我們的裝置都變成你的可推播對象啦,沒啥不好吧!至少開放幾天讓我們測試一下)