Reputation: 3171
I'm trying to use this Web Push walk-through to allow my customers to get push notifications sent to their phones/desktops: https://framework.realtime.co/demo/web-push/
The demo on the site is working for me, and when I copy it over to my server I'm able to push messages down and I see them being logged in the JavaScript console by my service worker with every push down the channel.
However, only the FIRST message pushed down the channel is causing a notification to appear, the rest simply don't show up. If I revoke the service-worker and reload the page (to get a new one) it works again -- for 1 push.
I'm using the same ortc.js file they are, an almost identical service-worker.js, modified with the ability to pass JSON for image/URL options. My modified service worker code is below.
I'm not getting any errors in the JS console (the 2 in the image above were from something else), but I am getting a red x icon next to the service worker, though the number next to it doesn't seem to be tied to anything I can tell (and clicking it does nothing; clicking the service-worker.js side just drops me to line 1 of the service-worker.js file, below.
My question is: why am I getting the first notification, but not any others? Or how can I go about debugging it? My JS console is showing the payloads, and stepping through the JS with breakpoints has me getting lost in the minified firebase code (I have tried both 3.5 and 6.5 for the firebase.js files).
Here is my service worker:
// 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;
}
}
Upvotes: 3
Views: 2527
Reputation: 258
I had a similar problem. I was using the tag property from the options object. I gave a fixed value instead of a unique value. So only the first notification was showing up. Then I read this:
tag: An ID for a given notification that allows you to find, replace, or remove the notification using a script if necessary.
in the documentation and understand cause it needs to be a unique value. So now every notification is showing up. How I see also your tag variable is hardcodated.
Upvotes: 2