![](/img/trans.png)
[英]Desktop push notification using Google cloud messaging and service worker
[英]Service Worker only showing first push notification (from cloud messaging) until I reload - message IS received by the worker
我正在嘗試使用此 Web Push 演練來允許我的客戶將推送通知發送到他們的手機/桌面: https : //framework.realtime.co/demo/web-push/
站點上的演示對我有用,當我將其復制到我的服務器時,我能夠向下推送消息,並且每次向下推送通道時,我都會看到它們被我的服務工作者記錄在 JavaScript 控制台中。
但是,只有在頻道下推的第一個消息會導致出現通知,其余的根本不顯示。 如果我撤銷 service-worker 並重新加載頁面(以獲取新頁面),它會再次運行 - 1 次推送。
我正在使用與它們相同的 ortc.js 文件,一個幾乎相同的 service-worker.js,修改為能夠為圖像/URL 選項傳遞 JSON。 我修改后的服務工作者代碼如下。
我在 JS 控制台中沒有收到任何錯誤(上圖中的 2 來自其他東西),但是我在 service worker 旁邊看到了一個紅色的 x 圖標,盡管它旁邊的數字似乎不是與我能說出的任何事情相關聯(單擊它什么也不做;單擊 service-worker.js 一側只會將我帶到下面的 service-worker.js 文件的第 1 行。
我的問題是:為什么我會收到第一個通知,而不是其他任何通知? 或者我該如何調試它? 我的 JS 控制台正在顯示有效載荷,並且通過斷點單步執行 JS 讓我迷失在縮小的 firebase 代碼中(我已經為 firebase.js 文件嘗試了 3.5 和 6.5)。
這是我的服務人員:
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/3.5.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.0/firebase-messaging.js');
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
'messagingSenderId': '580405122074'
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const fb_messaging = firebase.messaging();
// Buffer to save multipart messages
var messagesBuffer = {};
// Gets the number of keys in a dictionary
var countKeys = function (dic) {
var count = 0;
for (var i in dic) {
count++;
}
return count;
};
// Parses the Realtime messages using multipart format
var parseRealtimeMessage = function (message) {
// Multi part
var regexPattern = /^(\w[^_]*)_{1}(\d*)-{1}(\d*)_{1}([\s\S.]*)$/;
var match = regexPattern.exec(message);
var messageId = null;
var messageCurrentPart = 1;
var messageTotalPart = 1;
var lastPart = false;
if (match && match.length > 0) {
if (match[1]) {
messageId = match[1];
}
if (match[2]) {
messageCurrentPart = match[2];
}
if (match[3]) {
messageTotalPart = match[3];
}
if (match[4]) {
message = match[4];
}
}
if (messageId) {
if (!messagesBuffer[messageId]) {
messagesBuffer[messageId] = {};
}
messagesBuffer[messageId][messageCurrentPart] = message;
if (countKeys(messagesBuffer[messageId]) == messageTotalPart) {
lastPart = true;
}
}
else {
lastPart = true;
}
if (lastPart) {
if (messageId) {
message = "";
// Aggregate all parts
for (var i = 1; i <= messageTotalPart; i++) {
message += messagesBuffer[messageId][i];
delete messagesBuffer[messageId][i];
}
delete messagesBuffer[messageId];
}
return message;
} else {
// We don't have yet all parts, we need to wait ...
return null;
}
}
// Shows a notification
function showNotification(message, settings) {
// In this example we are assuming the message is a simple string
// containing the notification text. The target link of the notification
// click is fixed, but in your use case you could send a JSON message with
// a link property and use it in the click_url of the notification
// The notification title
var notificationTitle = 'Web Push Notification';
var title = "Company Name";
var icon = "/img/default.png";
var url = "https://www.example.com/";
var tag = "same";
if(settings != undefined) {
if(hasJsonStructure(settings)) settings = JSON.parse(settings);
title = settings.title;
icon = settings.icon;
url = settings.click_url;
tag = "same";
}
// The notification properties
const notificationOptions = {
body: message,
icon: icon,
data: {
click_url: url
},
tag: tag
};
return self.registration.showNotification(title,
notificationOptions);
}
// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
fb_messaging.setBackgroundMessageHandler(function(payload) {
console.log('Received background message ', payload);
// Customize notification here
if(payload.data && payload.data.M) {
var message = parseRealtimeMessage(payload.data.M);
return showNotification(message, payload.data.P);
}
});
// Forces a notification
self.addEventListener('message', function (evt) {
if(hasJsonStructure(evt.data)) {
var opts = JSON.parse(evt.data);
var message = opts.message;
evt.waitUntil(showNotification(message, opts));
}
else evt.waitUntil(showNotification(evt.data));
});
// The user has clicked on the notification ...
self.addEventListener('notificationclick', function(event) {
// Android doesn’t close the notification when you click on it
// See: http://crbug.com/463146
event.notification.close();
if(event.notification.data && event.notification.data.click_url) {
// gets the notitication click url
var click_url = event.notification.data.click_url;
// This looks to see if the current is already open and
// focuses if it is
event.waitUntil(clients.matchAll({
type: "window"
}).then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
if (client.url == click_url && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
var url = click_url;
return clients.openWindow(url);
}
}));
}
});
function hasJsonStructure(str) {
if (typeof str !== 'string') return false;
try {
const result = JSON.parse(str);
const type = Object.prototype.toString.call(result);
return type === '[object Object]'
|| type === '[object Array]';
} catch (err) {
return false;
}
}
我有一個類似的問題。 我正在使用選項對象中的 tag 屬性。 我給出了一個固定值而不是一個唯一值。 所以只出現了第一個通知。 然后我讀了這個:
標簽:給定通知的 ID,允許您在必要時使用腳本查找、替換或刪除通知。
在文檔中並理解原因它需要是一個唯一的值。 所以現在每個通知都出現了。 我如何看待你的標簽變量是硬編碼的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.