天天看點

FCM接入總結編寫目的參考資料

編寫目的

FCM官方文檔中描述比較零散,我自己在調研接入方式時也耗費了一些時間,是以我想編寫一個文檔,對接入FCM前後端的改造點做一個完整的描述,也算是對FCM調研過程做一個總結,希望能給有相關需求的人一些參考,文檔會分為FCM服務申請,WEB端SDK接入,伺服器端消息發送三個部分來描述,所有的項目代碼都在github:https://github.com/caixunshi/go-fcm-example

歡迎大家star

參考資料

FCM官方文檔

一、FCM服務申請

谷歌推送以前叫GCM,在2019年4月11日遷移到了firebase cloud message(FCM),我們要使用FCM,需要在firebase上建立一個項目,是以需要有一個gmail郵箱

1.1 添加項目

通路https://console.firebase.google.com/,登陸後可以看到以下界面:

然後點選Add project,建立一個firebase項目

1.2 擷取應用憑證

建立号項目之後,點選項目→進入控制台 → 點選設定

FCM接入總結編寫目的參考資料

然後在正常資訊欄中,檢視到web應用憑證,這裡也提供了npm和cdn的內建方式示例

FCM接入總結編寫目的參考資料

應用憑證是用來給到前端內建SDK與FCM建立長連結,這裡我們這裡的應用憑證是:

{
    apiKey: "AIzaSyAUVTaipaExXUTGGc7e-A3gUiA3Q8i7O8Y",
    authDomain: "shipment-portal-1f1b3.firebaseapp.com",
    projectId: "shipment-portal-1f1b3",
    storageBucket: "shipment-portal-1f1b3.appspot.com",
    messagingSenderId: "333922912996",
    appId: "1:333922912996:web:18467f5642e6fba00efaf1",
    measurementId: "G-5HNY007WZW"
}
           

然後在回到雲消息傳遞資訊欄,檢視到伺服器密鑰

FCM接入總結編寫目的參考資料

伺服器密鑰用來向FCM推送消息,然後由FCM通過長連結推送給web用戶端

伺服器密鑰用來可以添加多個,這裡我們使用的密鑰是:

AAAAjaT6Kls:APA91bFki15CULQgVFGKn1N3cR-PlKhcU5wMEClTl5NtP9YQylHSBsJctlZzQ0sdp6TnOsp5jyzzqW4tzSVDneKCmP8XQ8ZgA8w6wk6AW28aAdZn6eyz0U-OA7TuJ2WlkBbS10KcxQHe
           

二、前端項目內建firebase sdk

前端可以通過npm或cdn的方式将fcm內建進自己的web項目,這裡我用cdn的方式做示例,npm的操作方式可以參考:https://firebase.google.com/docs/web/setup

2.1 建立index.html

在界面上我們添加了一個accountId的輸入框,點選登入之後,會将accountId和目前web用戶端的token發送給伺服器,用來模拟使用者登陸的場景,界面如下:

FCM接入總結編寫目的參考資料

在onload中我們初始化firebase,并通過requestPermission方法請求使用者允許發送通知,然後注冊了一個messaging.onMessage監聽,當FCM通過長連結推送消息到web用戶端時,并且web應用位于前台時,會執行onMessage方法,請求使用者允許通知界面如下:

FCM接入總結編寫目的參考資料

index.html的所有代碼如下:

<html xmlns="http://www.w3.org/1999/html">
<body>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js"></script>
<h1>FCM</h1>
account: <input id="accountId"/>
<input type="button" value="login" onclick="login()"/>
<div id="info"></div>
<div id="msg" style="font-size:64px;color:red">0</div>
</body>
<script>
    var accessToken = "123123"

    // 定義配置檔案
    var firebaseConfig = {
        apiKey: "AIzaSyBqBrEAaRBXhqtOaHaknfNV4_27Go2P3zE",
        authDomain: "weqwe-d71c5.firebaseapp.com",
        projectId: "weqwe-d71c5",
        storageBucket: "weqwe-d71c5.appspot.com",
        messagingSenderId: "608358247003",
        appId: "1:608358247003:web:433e10a50f5f51a5db2d7e",
        measurementId: "G-4QGGNLHSWW"
    };
    function login() {
        var accountId = document.getElementById("accountId").value
        // 注冊token到背景
        document.getElementById("info").innerHTML = "token: " + accessToken
        resp = fetch("http://localhost:8090/accessToken", {
            method: "POST",
            mode:"cors",
            headers: {
                "Content-type": 'application/json;charset=utf-8'
            },
            body: JSON.stringify({"accountId": accountId, "token": accessToken}),
        })
        console.log(resp);
    }
    window.onload  = function () {
        // 生成token
        firebase.initializeApp(firebaseConfig);
        var messaging = firebase.messaging();
        messaging.requestPermission()
            .then(function () {
                return messaging.getToken();
            })
            .then(function (token) {
                accessToken = token
            })
            .catch(function (err) {
                console.log('Unable to get permission to notify.', err);
            });

        // 注冊監聽事件
        messaging.onMessage(function (payload) {
            // 更新清單消息數量
            console.log('Message received. ', payload);
            var msg = document.getElementById("msg").innerHTML
            document.getElementById("msg").innerHTML = Number(msg) + 1
        });
    }

</script>
</html>
           

2.2 建立firebase-messaging-sw.js

當使用者界面處于背景時,是無法觸發onMessage方法,firebasebase基于service work提供了onBackgroundMessage方法,我們在index.html同目錄下建立一個firebase-messaging-sw.js,然後注冊一個onBackgroundMessage方法

代碼如下:

importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
    apiKey: "AIzaSyAUVTaipaExXUTGGc7e-A3gUiA3Q8i7O8Y",
    authDomain: "shipment-portal-1f1b3.firebaseapp.com",
    projectId: "shipment-portal-1f1b3",
    storageBucket: "shipment-portal-1f1b3.appspot.com",
    messagingSenderId: "333922912996",
    appId: "1:333922912996:web:18467f5642e6fba00efaf1",
    measurementId: "G-5HNY007WZW"
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
    console.log('Received background message ', payload);
    // console.log(self)
    var title = payload.data.title
    var options = {
        body: payload.data.body,
        icon: payload.data.url
    }
    self.registration.showNotification(title,
        options);
});
           

我們在onBackgroundMessage中通過showNotification彈出一個彈框,當web應用處于背景時(使用者未停留在web界面),有FCM傳遞過來的新消息,會彈出一個彈框,效果如下:

FCM接入總結編寫目的參考資料

三、後端項目發送通知消息

3.1 互動流程圖

FCM接入總結編寫目的參考資料

3.2 建立Admin項目

建立一個Admin項目模拟我們的背景,主要是提供了查詢線上使用者清單,登陸,發送消息三個基本功能,用來模拟和web端的互動,admin的界面如下:

FCM接入總結編寫目的參考資料
  • 查詢線上使用者清單:使用者初始化SDK成功之後,我們需要将使用者的accountId和目前的token儲存起來;
  • 登陸:在使用者web界面,點選login之後會将accountId和token傳遞給背景進行儲存;
  • 發送消息:輸入需要發送的accountId和title body,url之後,點選send,消息内容達到背景之後,會通過POST請求發給FCM;

四、總結

4.1 項目代碼:

FCM接入總結編寫目的參考資料

4.2 後端啟動

後端是基于gin建構,直接啟動main函數即可啟動

4.3 前端啟動

靜态資源的部署有很多種方式,一般我們可以利用nginx去部署,這裡我們利用http-server這種更加輕量的方式啟動一個http-server伺服器,http-server是一個輕量級的基于nodejs的http伺服器,可以使任意一個目錄成為伺服器的目錄,完全抛開背景的沉重工程,直接運作想要的js代碼。

4.2.1 安裝node

直接下載下傳安裝即可,官網位址: https://nodejs.org

安裝成功之後在指令行輸入指令$ node -v以及$ npm -v檢查版本,确認是否安裝成功。

4.2.2 安裝http-server

打開終端輸入:

npm install http-server -g

安裝成功之後進入目标檔案夾,這裡就是我們項目的 front/src

然後輸入:

http-server

這樣就會在本地8080端口啟動一個http伺服器(如果8080被占用則會在8081端口啟動,以此類推),啟動界面如下:

FCM接入總結編寫目的參考資料

使用者web界面為:http://localhost:8080/index.html

後端管理界面為:http://localhost:8080/admin.html

這樣我們就可以在兩個浏覽器分别測試消息發送啦

PS: 使用者web界面谷歌浏覽器service work不支援非https,是以不能測試使用者離開web界面的彈框提醒場景,隻能測試使用者停留在web界面接受消息的場景,需要看效果的可以用firefox

4.3 思考

  • 使用者初始化SDK并與FCM建立長連結是沒有傳入業務參數的,生成出來的token是跟我們的業務資料(如使用者)無關的,是以我們需要用戶端主動上報token 和 username,并在我們自己的背景維護這個關系,但這也衍生出來幾個問題,需要根據具體的業務場景去制定解決方案。
  • 使用者在多個端(比如多個浏覽器)登陸時,一個使用者會有多個token,如果想要所有端都通知的話,就需要保留所有的token,否則就隻有最後登陸的端能接收到消,使用者量很大的情況下,儲存這個關系需要成本;

    使用者下線之後,伺服器的token和user的關聯關系如何删除?(直接關掉web界面或直接kill 掉 app);

繼續閱讀