quickstart-js: Don't show notification in setBackgroundMessageHandler

I have a question about the setBackgroundMessageHandler. According to all of the documentation / examples the return value of your handler should be a promise that shows a notification. But there are some cases in which I don’t want to show a notification. For example,

messaging.setBackgroundMessageHandler( payload => {
  return self.clients.claim().then(() => {
    return self.clients.matchAll({type: 'window'}).then(clients => {
      if (somethingGood) {
        return self.registration.showNotification('Title', {body: 'Body', icon: '/icon.png'});
      } else {
        // DON'T SHOW ANYTHING
      }
    })
  })
});

In place of DON'T SHOW ANYTHING I have also tried:

return null;
return {};
return () => {};
return Promise.resolve();

…and so on. But no matter what I return I always see a notification (in Chrome) that looks like:

image

Is there any value I can return that will not display a notification?

Thanks for any help!

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 12
  • Comments: 35

Most upvoted comments

In case anyone needs this: I resolved this by returning an empty Promise when I don’t want to show the notification in setBackgroundMessageHandler

  if (somethingGood) {
    return self.registration.showNotification('Title', {body: 'Body', icon: '/icon.png'});
  } else {
    // DON'T SHOW ANYTHING
   return new Promise(function(resolve, reject) {});
  }

Any updates on this?

The closest that I was able to get is by hiding the message after some milliseconds:

messaging.setBackgroundMessageHandler(function(payload) {
    console.log('[firebase-messaging-sw.js] Received background message', payload);
    return new Promise(function(resolve, reject) {
        resolve();
        setTimeout(function(){
            self.registration.getNotifications().then(notifications => {  
                notifications.forEach((notification) => { 
                    notification.close();
                })
            })
        },10);
    });
});

In case anyone needs this: I resolved this by returning an empty Promise when I don’t want to show the notification in setBackgroundMessageHandler

  if (somethingGood) {
    return self.registration.showNotification('Title', {body: 'Body', icon: '/icon.png'});
  } else {
    // DON'T SHOW ANYTHING
   return new Promise(function(resolve, reject) {});
  }

The notification doesn’t show immediately but it is eventually shown after 90 seconds.

Hey! Any update?? To not show the default notification.

You can delete the token which will unsubscribe the user as well.

@roiboos you are essentially creating a a promise that never resolve and therefore an evant.waitUntill that will never resolve. won’t this create a memory leak?

If the page is open and focused you don’t have to show a notification and as a result you’ll receive a callback in onMessage in the page.

If the page is in the background (i.e. not focused) the background message handler will be called and you have to show a notification, otherwise you get the default notification you added as a screenshot.

It’s Chrome that shows the message, not the SDK -this is a browser restriction.

Chrome currently only supports the Push API for subscriptions that will result in user-visible messages. You can indicate this by calling pushManager.subscribe({userVisibleOnly: true}) instead. See https://goo.gl/yqv4Q4 for more details.

The restriction from Chrome forces back-end to track each notification instead of sending the data directly. In architecture terms it’s called PLOP - place oriented programming (degradatory term for OOP). Instead I would prefer DOP - data oriented programming. Where data comes in gradually and the client decides what they want. Maybe to show a notification, maybe a persistent notification, maybe hide past notification, maybe nothing. But this kind of policy also allows to send less data overall. It’s a tradeoff.

Also one important problem with this is that the service worker has to have its own state, each browser tab has its own state already and each user’s device has their own state. So SW has to broadcast messages to the app because the app may need to react to them (if there are multiple background tabs and you wish to sync them somehow).

Data orchestration between devices is pretty rough as well because sometimes something complex may be triggered from backend. For instance it could be a series of events where if you miss the first one or first one doesn’t apply to you you should miss or still get all others without notifications. So if it involves multiple users that have more than one device… then in that scenario the back-end has to track which user, which device and what messages it should show instead only tracking a single user… that’s pretty rough.

And on top of that backend can’t know which device is sleeping with service worker active and which device is active and is in foreground. And also back-end can’t mark messages “not deliver if in SW-only mode” because there is no such flag" and I would like to ignore messages based on this. It can know that SW is inactive by sending a push message and getting an error. But that’s not good enough because active SW means a notification but there is no way to know if the app is alive otherwise (yes, this can be used for tracking and it’s not good to do it witout notifying the user but I’m not sure what to do here).

return new Promise(function(resolve, reject) { resolve(); setTimeout(function(){ self.registration.getNotifications().then(notifications => {
notifications.forEach((notification) => { notification.close(); }) }) },10); });

this solved my problem!

tks ! xD

@mrbig00 - thanks, we’re not yet on Android Chrome, wish I could offer help. Hopefully others could comment as to other browsers and platforms.