昨天我們拿到Public Key
和Private Key
,現在要來使用這些權限,
讓伺服器成功推播訊息到使用者裝置上。
使用者新增文章的時候,會觸發之前我們串好firebase
的功能(storePostData()
),
現在當觸發該方法的時候,除了回傳成功上傳訊息時,順便從firebase
上,抓取subscriptions
資料表中,所有訂閱使用者,並發送推播訊息。
首先開啟functions/index.js
,因為要模擬從firebase
準備訊息
推播給用戶端手機,勢必我們訊息必須寫在伺服器端。
接著找到storePostData()
exports.storePostData = functions.https.onRequest(function(request, response) {
cors(request, response, function(){
admin.database().ref('article').push({
//..之前的程式
})
.then(function(){
webpush.setVapidDetails('mailto:monkey030210@gmail.com',
vapidKeys.publicKey,
vapidKeys.privateKey
);
return admin.database().ref('subscriptions').once('value');
})
.then(function(subs){
subs.forEach(function(sub){
var pushConfig = {
endpoint: sub.val().endpoint,
keys: {
auth: sub.val().keys.auth,
p256dh: sub.val().keys.p256dh
}
};
webpush.sendNotification(pushConfig, JSON.stringify({title: '回來逛逛哦', content: '再撐一下就到30天啦'}))
.catch(function(err){
console.log('Server 推播失敗',err);
});
});
response.status(201).json({message: '資料送出', id: request.body.id});
})
.catch(function(err) {
response.status(500).json({error: err});
});
});
})
好長一段程式阿,來分段解釋一下
var webpush = require('web-push');
var vapidKeys = {
publicKey: 'BNaAfuqm_lOcGE8H8z-ad1BjE3gBmDQDppECZC1btjfVs4fpSAJbKUujBa31GYiUzOmwHQW4FX1qxGfXTsqBym8',
privateKey: 'GKukjt9CaJccs88FK7Wqt3MrH9E9EmqOLjYYodZukZY'
}
這邊我們需要先引用web-push
才能使用該功能,
另外建立一個物件(非必要),放昨天拿到的公鑰和私鑰。
.then(function(){
webpush.setVapidDetails('mailto:monkey030210@gmail.com',
vapidKeys.publicKey,
vapidKeys.privateKey
);
return admin.database().ref('subscriptions').once('value');
})
接著webpush.setVapidDetails()
用來設定推播前的資格驗證,第一個可以放URL
或是Mail
用途是當Push Server
如果要回傳一些資訊時,他們會直接傳到上面的E-mail。
後面放Key
。
並回傳subscriptions
的內容,once
一樣回傳型別是Promise
.then(function(subs){
subs.forEach(function(sub){
var pushConfig = {
endpoint: sub.val().endpoint,
keys: {
auth: sub.val().keys.auth,
p256dh: sub.val().keys.p256dh
}
};
webpush.sendNotification(pushConfig, JSON.stringify({title: '回來逛逛哦', content: '再撐一下就到30天啦'}))
.catch(function(err){
console.log('Server 推播失敗',err);
});
});
response.status(201).json({message: '資料送出', id: request.body.id});
})
.catch(function(err) {
response.status(500).json({error: err});
});
forEach
可以尋訪所有物件內容,這裡一樣建一個物件存放每個訂閱裝置的三個資料內容,webpush.sendNotification
,透過此方法,傳送推播訊息給使用者,第一個參數放發送推播所需的endpoint
和key
,後面則是傳送一組Json
格式的資料,最後成功顯示這串字,就代表我們成功啦
後面一樣接catch
方便抓取錯誤訊息。
在firebase
中,嘗試傳送推播訊息,但如果沒有寫push
監聽事件,是不會有任何事情發生的,因為用戶端的Service Worker
並沒有接口來接訊息。
self.addEventListener('push', function(event){
console.log('收到推播訊息', event);
var contentObj = {title: '新訊息', content: '預設訊息,會被伺服器訊息覆蓋'};
if(event.data){
contentObj = JSON.parse(event.data.text());
}
var options = {
body: contentObj.content,
icon: '/src/images/icons/demo-icon96.png',
lang: 'zh-Hant', //BCP 47
vibrate: [100, 50, 200],
badge: '/src/images/icons/demo-icon96.png',
tag: 'first-notification'
};
event.waitUntil(
self.registration.showNotification(contentObj.title, options)
);
});
這裡設定一組contentObj
,裡面存含預設內容的title
和content
假設觸發push
時,收到的推播內容,理應覆蓋掉上面的預設值
假設event.data
不是空值,就將在firebase
推送的Json
格式的物件內容,
覆蓋contentObj
的值。
後面就是開始寫推播的設定,在Service Worker
,使用self.registration.showNotification(標題, 推播設定)
來顯示訊息
填寫發文表單
點選「發佈」
結果
右下角成功顯示,在伺服器撰寫的訊息內容Console
視窗也看到成功訊息。
在修改程式時,前面我們習慣每次修改後,更改版號和清除瀏覽器上所有快取資源。
但因為訂閱是綁定裝置瀏覽器的,還記得綁定成功時,會存有endpoint
和key
到伺服器,
假如清除快取資料,也解除裝置上的Service Worker
,那麼我們綁定的鑰匙與endpoint
則會無法對應,造成失敗的現象。
所以在修改程式後,記得不要清除網站所有快取,只需要更新版號,重整網頁,並手動觸發activate
來更新快取住的檔案。
[https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications](google: 介紹推播)
https://github.com/DakHarry/30day-pwas-practice