'FCM Web Notification click action focus on last tab
I am having a problem with fcm web notification.
The problem arises only on ANDROID devices.
It works in all of these situations opening a new tab:
- chrome is completely closed
- chrome is open and has an active tab with source domain
But if I leave chrome open in the background for some time, when the notification arrives it puts me the on focus on the last tab without being able to reach the click action.
self.addEventListener('notificationclick', function (event) {
var url = event.notification.data;
console.log('On notification click: ', event);
event.notification.close(); // Android needs explicit close.
event.waitUntil(
clients.matchAll({ includeUncontrolled: true, type: 'window' }).then(windowClients => {
// Check if there is already a window/tab open with the target URL
for (var i = 0; i < windowClients.length; i++) {
var client = windowClients[i];
// If so, just focus it.
if (client.url === url && 'focus' in client) {
// return client.focus();
}
}
// If not, then open the target URL in a new window/tab.
if (clients.openWindow) {
// document.cookie = 'notificationDisabledBool=false; expires=Sun, 1 Jan 2026 00:00:00 UTC; path=/'
// return clients.openWindow(url);
}
return clients.openWindow(url);
})
);
});
I remove client.focus() and remain only openWindow().
Where is the problem?
Solution 1:[1]
Well, you've helped me figure out some things. Here's what I've got going on, maybe it will help you -- or someone else. I'm not using the Firebase stuff, and I assume your code is in a service worker. Further, I assume you're passing the url as a simple string when the notification is created, since you have: var url = event.notification.data;
...I use an object. (Also, I see that you are trying to do something with cookies:
// document.cookie = 'notificationDisabledBool=false; expires=Sun, 1 Jan 2026 00:00:00 UTC; path=/'
I thought the service workers did not have access to cookies....
Anyway, here's my code, which seems to work as of today, on Android:
// holds BroadcastChannel instances; BC.all = all browser pages; BC[game_num] = just the one game
const BC = {};
const browser_has_BC = (self.BroadcastChannel) ? true : false;
if (browser_has_BC) {
set_up_BC_all();
}
else {
console.log("The JavaScript game client would like to use BroadcastChannel. " +
"Please update your browser software.");
}
function set_up_BC_all() {
BC.all= new BroadcastChannel('all');
BC.all.postMessage({ payload: `BC_all sw.js SW_VERSION = ${SW_VERSION}` });
}
// this will listen for clicks on push notification banners; the push notification will have
// the game_num in the data parameter, which we will use to make a unique BroadcastChannel
// for that particular game -- if it hasn't already been created; we will then use that game_num
// channel to communicate with the JS client of that game; n.b. postMessage payload can be complex obj
self.addEventListener('notificationclick', function sw_notificationclick (event) {
// data passed via to the showNotification func when the main page had this sw create it;
// we'll now use url to find which window we want to focus(), or to openWindow(url) if
// it has been closed by the user; n.b. openWindow seems to use the web app on Android
// instead of calling up the web browser (cool!)
const game_num = event.notification.data.game_num;
const notification_url = event.notification.data.url;
console.log(`SW: sw_notificationclick notification_url=${notification_url} event=`, event);
// let the window for this specific game know that the notification has been clicked;
// it will then close the 'your turn' msg popup so the user needn't
try {
if (browser_has_BC) {
if (!BC[game_num]) { BC[game_num] = new BroadcastChannel(game_num); }
const payload_obj = { event_type: 'notificationclick' };
BC[game_num].postMessage({ payload: payload_obj });
}
}
catch (error) {
console.log("SW: error in notificationclick handler=", error);
}
event.waitUntil(
clients.matchAll({ includeUncontrolled: true, type: 'window' }).then((client_list) => {
for (var i = 0; i < client_list.length; i++) {
const client = client_list[i];
console.log(`client_list[${i}]=`, client);
if (client.url == notification_url && 'focus' in client) { return client.focus(); }
}
if (clients.openWindow) { return clients.openWindow(notification_url); }
}).catch((error) => { console.log("SW: error in notificationclick handler=", error); })
);
event.notification.close();
}, false);
I also note that I am doing event.notification.close() at the end -- maybe that is a factor.
Another observation I made: when I had my game installed as a web app, i.e. added to the home screen, and there was no tab open in the browser for the URL, the clients.openWindow() opened the page in the web app! Exciting!
Anyway, hope this helps someone.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
