iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 28
1

昨天我們拿到Public KeyPrivate Key,現在要來使用這些權限,
讓伺服器成功推播訊息到使用者裝置上。

情境

使用者新增文章的時候,會觸發之前我們串好firebase的功能(storePostData()),
現在當觸發該方法的時候,除了回傳成功上傳訊息時,順便從firebase上,抓取subscriptions資料表中,所有訂閱使用者,並發送推播訊息。

Step1: 撈取要推播的訂閱戶

Step2: 將訊息透過endpoint推播給所有用戶

首先開啟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,透過此方法,傳送推播訊息給使用者,第一個參數放發送推播所需的endpointkey,後面則是傳送一組Json格式的資料,最後成功顯示這串字,就代表我們成功啦
後面一樣接catch方便抓取錯誤訊息。

Step3: Service Worker新增push監聽事件

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,裡面存含預設內容的titlecontent
假設觸發push時,收到的推播內容,理應覆蓋掉上面的預設值
假設event.data不是空值,就將在firebase推送的Json格式的物件內容,
覆蓋contentObj的值。
後面就是開始寫推播的設定,在Service Worker,使用self.registration.showNotification(標題, 推播設定)來顯示訊息

測試

  1. 填寫發文表單
    https://ithelp.ithome.com.tw/upload/images/20180114/20103808EotBCm40cT.png
    點選「發佈」

  2. 結果
    https://ithelp.ithome.com.tw/upload/images/20180114/20103808RQjnXoj5ld.png
    右下角成功顯示,在伺服器撰寫的訊息內容
    https://ithelp.ithome.com.tw/upload/images/20180114/20103808hJahxBMWgQ.png
    Console視窗也看到成功訊息。

注意事項

在修改程式時,前面我們習慣每次修改後,更改版號和清除瀏覽器上所有快取資源。
但因為訂閱是綁定裝置瀏覽器的,還記得綁定成功時,會存有endpointkey到伺服器,
假如清除快取資料,也解除裝置上的Service Worker,那麼我們綁定的鑰匙與endpoint則會無法對應,造成失敗的現象。
所以在修改程式後,記得不要清除網站所有快取,只需要更新版號,重整網頁,並手動觸發activate來更新快取住的檔案。

閱讀資源

[https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications](google: 介紹推播)

GitHub

https://github.com/DakHarry/30day-pwas-practice


上一篇
Day27-Push Notification之成為訂閱用戶(Firebase實作)
下一篇
Day29-Workbox Tool
系列文
30天走訪Progressive Web Apps(PWAs)30

尚未有邦友留言

立即登入留言