Can't get custom push notification event working in PWA (Firebase)











up vote
0
down vote

favorite












I've been searching for a few hours on how to get my custom push notification working. Here is how I've set up my project: no front-end framework, a Node.js/Express.js back-end, Firebase Cloud Messaging (FCM) as push manager and a custom service worker. I am currently hosting the app on localhost and I have HTTPS set up and a manifest.json that contains the minimum amount of fields to get started. The manifest.json contains a start_url field that points to /index.html, the landing page for the app. The app is bundled with webpack v. 4.



Back-end



On the back-end, I have set up the Firebase Admin SDK in a specific router and I send a custom notification object a bit like the following to the FCM server:



let fcMessage = {
data : {
title : 'Foo',
tag : 'url to view that opens bar.html'
}
};


When an interesting event occurs on the back-end, it retrieves a list of users that contains the FCM registration tokens and sends the notification to the FCM servers. This part works great.



Front-end



I have two service workers on the front-end. Inside my front-end index.js, I register a custom service worker named sw.js in the domain root and tell firebase to use that service worker like so:



if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(registration => {
messaging.useServiceWorker(registration);
})
.catch(err => console.error(`OOps! ${err}`));
}


FCM and its credentials are set up and the user can subscribe to push notifications. I won't show that code here since it works and I don't believe it is the issue.



Now on to the service workers themselves. I have a firebase-messaging-sw.js file at the root of my domain. It contains the following code:



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

firebase.initializeApp(configuration);
const messaging = firebase.messaging();


Configuration is just a placeholder for all of the creds. Again that stuff works.



What I want to do is to NOT use the FCM push notification and instead create my own push notification that contains a url to a view that the user can click on and go to that view. The following code almost works and is a hack I found on another site:



class CustomPushEvent extends Event {
constructor(data) {
super('push');

Object.assign(this, data);
this.custom = true;
}
}
self.addEventListener('push', (e) => {
console.log('[Service Worker] heard a push ', e);
// Skip if event is our own custom event
if (e.custom) return;

// Keep old event data to override
let oldData = e.data;

// Create a new event to dispatch
let newEvent = new CustomPushEvent({
data: {
json() {
let newData = oldData.json();
newData._notification = newData.notification;
delete newData.notification;
return newData;
},
},

waitUntil: e.waitUntil.bind(e),
})

// Stop event propagation
e.stopImmediatePropagation();

// Dispatch the new wrapped event
dispatchEvent(newEvent);
});

messaging.setBackgroundMessageHandler(function(payload) {
if (payload.hasOwnProperty('_notification')) {
return self.registration.showNotification(payload.data.title,
{
body : payload.data.text,
actions : [
{
action : `${payload.data.tag}`,
title : 'Go to link'
}
]
});
} else {
return;
}
});

self.addEventListener('notificationclick', function(e) {
console.log('CLICK');

e.notification.close();

e.waitUntil(clients.matchAll({ type : 'window' })
.then(function(clientList) {
console.log('client List ', clientList);
const cLng = clientList.length;
if (clientList.length > 0) {
for (let i = 0; i < cLng; i++) {
const client = clientList[i];

if (client.url === '/' && 'focus' in client) {
return client.focus();
}
}
} else {
console.log('no clients ', e.action);
clients.openWindow(e.action)
.then(client => {
console.log('client ', client);
return client.navigate(e.action);
})
.catch(err => console.error(`[Service Worker] cannot open client : ${err} `));
}
}))
});


The hack is meant to capture a push event and the FCM default notification payload and instead serve that payload through a custom one made via the Notification API.



The code above works great but ONLY if I put it in the firebase-messaging-sw.js file. That's not what I really want to do: I want to put it in the sw.js file instead but when I do, the sw.js cannot hear any push events and instead I get the default FCM push notification. I've also tried importing the entire firebase-messaging-sw scripts into the custom service worker and it still won't hear the message events.



Why do I want to use it in my service worker instead of the Firebase one? It's to be able to open the app on the view passed into the 'tag' field on the notification's body. If I use the Firebase service worker, it tells me that it's not the active registered service worker and though the app does open in a new window, it only opens on /index.html.



Some minor observations I've made: the clients array is always empty when the last bit of code is added to the firebase-messaging-sw.js file. The custom service worker is installed properly because it handles the app shell cache and listens to all of the other events normally. The firebase-messaging-sw service worker is also installed properly.










share|improve this question




























    up vote
    0
    down vote

    favorite












    I've been searching for a few hours on how to get my custom push notification working. Here is how I've set up my project: no front-end framework, a Node.js/Express.js back-end, Firebase Cloud Messaging (FCM) as push manager and a custom service worker. I am currently hosting the app on localhost and I have HTTPS set up and a manifest.json that contains the minimum amount of fields to get started. The manifest.json contains a start_url field that points to /index.html, the landing page for the app. The app is bundled with webpack v. 4.



    Back-end



    On the back-end, I have set up the Firebase Admin SDK in a specific router and I send a custom notification object a bit like the following to the FCM server:



    let fcMessage = {
    data : {
    title : 'Foo',
    tag : 'url to view that opens bar.html'
    }
    };


    When an interesting event occurs on the back-end, it retrieves a list of users that contains the FCM registration tokens and sends the notification to the FCM servers. This part works great.



    Front-end



    I have two service workers on the front-end. Inside my front-end index.js, I register a custom service worker named sw.js in the domain root and tell firebase to use that service worker like so:



    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js')
    .then(registration => {
    messaging.useServiceWorker(registration);
    })
    .catch(err => console.error(`OOps! ${err}`));
    }


    FCM and its credentials are set up and the user can subscribe to push notifications. I won't show that code here since it works and I don't believe it is the issue.



    Now on to the service workers themselves. I have a firebase-messaging-sw.js file at the root of my domain. It contains the following code:



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

    firebase.initializeApp(configuration);
    const messaging = firebase.messaging();


    Configuration is just a placeholder for all of the creds. Again that stuff works.



    What I want to do is to NOT use the FCM push notification and instead create my own push notification that contains a url to a view that the user can click on and go to that view. The following code almost works and is a hack I found on another site:



    class CustomPushEvent extends Event {
    constructor(data) {
    super('push');

    Object.assign(this, data);
    this.custom = true;
    }
    }
    self.addEventListener('push', (e) => {
    console.log('[Service Worker] heard a push ', e);
    // Skip if event is our own custom event
    if (e.custom) return;

    // Keep old event data to override
    let oldData = e.data;

    // Create a new event to dispatch
    let newEvent = new CustomPushEvent({
    data: {
    json() {
    let newData = oldData.json();
    newData._notification = newData.notification;
    delete newData.notification;
    return newData;
    },
    },

    waitUntil: e.waitUntil.bind(e),
    })

    // Stop event propagation
    e.stopImmediatePropagation();

    // Dispatch the new wrapped event
    dispatchEvent(newEvent);
    });

    messaging.setBackgroundMessageHandler(function(payload) {
    if (payload.hasOwnProperty('_notification')) {
    return self.registration.showNotification(payload.data.title,
    {
    body : payload.data.text,
    actions : [
    {
    action : `${payload.data.tag}`,
    title : 'Go to link'
    }
    ]
    });
    } else {
    return;
    }
    });

    self.addEventListener('notificationclick', function(e) {
    console.log('CLICK');

    e.notification.close();

    e.waitUntil(clients.matchAll({ type : 'window' })
    .then(function(clientList) {
    console.log('client List ', clientList);
    const cLng = clientList.length;
    if (clientList.length > 0) {
    for (let i = 0; i < cLng; i++) {
    const client = clientList[i];

    if (client.url === '/' && 'focus' in client) {
    return client.focus();
    }
    }
    } else {
    console.log('no clients ', e.action);
    clients.openWindow(e.action)
    .then(client => {
    console.log('client ', client);
    return client.navigate(e.action);
    })
    .catch(err => console.error(`[Service Worker] cannot open client : ${err} `));
    }
    }))
    });


    The hack is meant to capture a push event and the FCM default notification payload and instead serve that payload through a custom one made via the Notification API.



    The code above works great but ONLY if I put it in the firebase-messaging-sw.js file. That's not what I really want to do: I want to put it in the sw.js file instead but when I do, the sw.js cannot hear any push events and instead I get the default FCM push notification. I've also tried importing the entire firebase-messaging-sw scripts into the custom service worker and it still won't hear the message events.



    Why do I want to use it in my service worker instead of the Firebase one? It's to be able to open the app on the view passed into the 'tag' field on the notification's body. If I use the Firebase service worker, it tells me that it's not the active registered service worker and though the app does open in a new window, it only opens on /index.html.



    Some minor observations I've made: the clients array is always empty when the last bit of code is added to the firebase-messaging-sw.js file. The custom service worker is installed properly because it handles the app shell cache and listens to all of the other events normally. The firebase-messaging-sw service worker is also installed properly.










    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I've been searching for a few hours on how to get my custom push notification working. Here is how I've set up my project: no front-end framework, a Node.js/Express.js back-end, Firebase Cloud Messaging (FCM) as push manager and a custom service worker. I am currently hosting the app on localhost and I have HTTPS set up and a manifest.json that contains the minimum amount of fields to get started. The manifest.json contains a start_url field that points to /index.html, the landing page for the app. The app is bundled with webpack v. 4.



      Back-end



      On the back-end, I have set up the Firebase Admin SDK in a specific router and I send a custom notification object a bit like the following to the FCM server:



      let fcMessage = {
      data : {
      title : 'Foo',
      tag : 'url to view that opens bar.html'
      }
      };


      When an interesting event occurs on the back-end, it retrieves a list of users that contains the FCM registration tokens and sends the notification to the FCM servers. This part works great.



      Front-end



      I have two service workers on the front-end. Inside my front-end index.js, I register a custom service worker named sw.js in the domain root and tell firebase to use that service worker like so:



      if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('./sw.js')
      .then(registration => {
      messaging.useServiceWorker(registration);
      })
      .catch(err => console.error(`OOps! ${err}`));
      }


      FCM and its credentials are set up and the user can subscribe to push notifications. I won't show that code here since it works and I don't believe it is the issue.



      Now on to the service workers themselves. I have a firebase-messaging-sw.js file at the root of my domain. It contains the following code:



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

      firebase.initializeApp(configuration);
      const messaging = firebase.messaging();


      Configuration is just a placeholder for all of the creds. Again that stuff works.



      What I want to do is to NOT use the FCM push notification and instead create my own push notification that contains a url to a view that the user can click on and go to that view. The following code almost works and is a hack I found on another site:



      class CustomPushEvent extends Event {
      constructor(data) {
      super('push');

      Object.assign(this, data);
      this.custom = true;
      }
      }
      self.addEventListener('push', (e) => {
      console.log('[Service Worker] heard a push ', e);
      // Skip if event is our own custom event
      if (e.custom) return;

      // Keep old event data to override
      let oldData = e.data;

      // Create a new event to dispatch
      let newEvent = new CustomPushEvent({
      data: {
      json() {
      let newData = oldData.json();
      newData._notification = newData.notification;
      delete newData.notification;
      return newData;
      },
      },

      waitUntil: e.waitUntil.bind(e),
      })

      // Stop event propagation
      e.stopImmediatePropagation();

      // Dispatch the new wrapped event
      dispatchEvent(newEvent);
      });

      messaging.setBackgroundMessageHandler(function(payload) {
      if (payload.hasOwnProperty('_notification')) {
      return self.registration.showNotification(payload.data.title,
      {
      body : payload.data.text,
      actions : [
      {
      action : `${payload.data.tag}`,
      title : 'Go to link'
      }
      ]
      });
      } else {
      return;
      }
      });

      self.addEventListener('notificationclick', function(e) {
      console.log('CLICK');

      e.notification.close();

      e.waitUntil(clients.matchAll({ type : 'window' })
      .then(function(clientList) {
      console.log('client List ', clientList);
      const cLng = clientList.length;
      if (clientList.length > 0) {
      for (let i = 0; i < cLng; i++) {
      const client = clientList[i];

      if (client.url === '/' && 'focus' in client) {
      return client.focus();
      }
      }
      } else {
      console.log('no clients ', e.action);
      clients.openWindow(e.action)
      .then(client => {
      console.log('client ', client);
      return client.navigate(e.action);
      })
      .catch(err => console.error(`[Service Worker] cannot open client : ${err} `));
      }
      }))
      });


      The hack is meant to capture a push event and the FCM default notification payload and instead serve that payload through a custom one made via the Notification API.



      The code above works great but ONLY if I put it in the firebase-messaging-sw.js file. That's not what I really want to do: I want to put it in the sw.js file instead but when I do, the sw.js cannot hear any push events and instead I get the default FCM push notification. I've also tried importing the entire firebase-messaging-sw scripts into the custom service worker and it still won't hear the message events.



      Why do I want to use it in my service worker instead of the Firebase one? It's to be able to open the app on the view passed into the 'tag' field on the notification's body. If I use the Firebase service worker, it tells me that it's not the active registered service worker and though the app does open in a new window, it only opens on /index.html.



      Some minor observations I've made: the clients array is always empty when the last bit of code is added to the firebase-messaging-sw.js file. The custom service worker is installed properly because it handles the app shell cache and listens to all of the other events normally. The firebase-messaging-sw service worker is also installed properly.










      share|improve this question















      I've been searching for a few hours on how to get my custom push notification working. Here is how I've set up my project: no front-end framework, a Node.js/Express.js back-end, Firebase Cloud Messaging (FCM) as push manager and a custom service worker. I am currently hosting the app on localhost and I have HTTPS set up and a manifest.json that contains the minimum amount of fields to get started. The manifest.json contains a start_url field that points to /index.html, the landing page for the app. The app is bundled with webpack v. 4.



      Back-end



      On the back-end, I have set up the Firebase Admin SDK in a specific router and I send a custom notification object a bit like the following to the FCM server:



      let fcMessage = {
      data : {
      title : 'Foo',
      tag : 'url to view that opens bar.html'
      }
      };


      When an interesting event occurs on the back-end, it retrieves a list of users that contains the FCM registration tokens and sends the notification to the FCM servers. This part works great.



      Front-end



      I have two service workers on the front-end. Inside my front-end index.js, I register a custom service worker named sw.js in the domain root and tell firebase to use that service worker like so:



      if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('./sw.js')
      .then(registration => {
      messaging.useServiceWorker(registration);
      })
      .catch(err => console.error(`OOps! ${err}`));
      }


      FCM and its credentials are set up and the user can subscribe to push notifications. I won't show that code here since it works and I don't believe it is the issue.



      Now on to the service workers themselves. I have a firebase-messaging-sw.js file at the root of my domain. It contains the following code:



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

      firebase.initializeApp(configuration);
      const messaging = firebase.messaging();


      Configuration is just a placeholder for all of the creds. Again that stuff works.



      What I want to do is to NOT use the FCM push notification and instead create my own push notification that contains a url to a view that the user can click on and go to that view. The following code almost works and is a hack I found on another site:



      class CustomPushEvent extends Event {
      constructor(data) {
      super('push');

      Object.assign(this, data);
      this.custom = true;
      }
      }
      self.addEventListener('push', (e) => {
      console.log('[Service Worker] heard a push ', e);
      // Skip if event is our own custom event
      if (e.custom) return;

      // Keep old event data to override
      let oldData = e.data;

      // Create a new event to dispatch
      let newEvent = new CustomPushEvent({
      data: {
      json() {
      let newData = oldData.json();
      newData._notification = newData.notification;
      delete newData.notification;
      return newData;
      },
      },

      waitUntil: e.waitUntil.bind(e),
      })

      // Stop event propagation
      e.stopImmediatePropagation();

      // Dispatch the new wrapped event
      dispatchEvent(newEvent);
      });

      messaging.setBackgroundMessageHandler(function(payload) {
      if (payload.hasOwnProperty('_notification')) {
      return self.registration.showNotification(payload.data.title,
      {
      body : payload.data.text,
      actions : [
      {
      action : `${payload.data.tag}`,
      title : 'Go to link'
      }
      ]
      });
      } else {
      return;
      }
      });

      self.addEventListener('notificationclick', function(e) {
      console.log('CLICK');

      e.notification.close();

      e.waitUntil(clients.matchAll({ type : 'window' })
      .then(function(clientList) {
      console.log('client List ', clientList);
      const cLng = clientList.length;
      if (clientList.length > 0) {
      for (let i = 0; i < cLng; i++) {
      const client = clientList[i];

      if (client.url === '/' && 'focus' in client) {
      return client.focus();
      }
      }
      } else {
      console.log('no clients ', e.action);
      clients.openWindow(e.action)
      .then(client => {
      console.log('client ', client);
      return client.navigate(e.action);
      })
      .catch(err => console.error(`[Service Worker] cannot open client : ${err} `));
      }
      }))
      });


      The hack is meant to capture a push event and the FCM default notification payload and instead serve that payload through a custom one made via the Notification API.



      The code above works great but ONLY if I put it in the firebase-messaging-sw.js file. That's not what I really want to do: I want to put it in the sw.js file instead but when I do, the sw.js cannot hear any push events and instead I get the default FCM push notification. I've also tried importing the entire firebase-messaging-sw scripts into the custom service worker and it still won't hear the message events.



      Why do I want to use it in my service worker instead of the Firebase one? It's to be able to open the app on the view passed into the 'tag' field on the notification's body. If I use the Firebase service worker, it tells me that it's not the active registered service worker and though the app does open in a new window, it only opens on /index.html.



      Some minor observations I've made: the clients array is always empty when the last bit of code is added to the firebase-messaging-sw.js file. The custom service worker is installed properly because it handles the app shell cache and listens to all of the other events normally. The firebase-messaging-sw service worker is also installed properly.







      javascript firebase push-notification firebase-cloud-messaging progressive-web-apps






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 at 15:32

























      asked Nov 20 at 11:43









      Testinnplayin

      11




      11
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          After much pain and aggravation, I figured out what the problem was. It was a combination of the architecture of the app (that is, a traditional Multi-Page App) and a badly-formed url in the custom service worker, sw.js as so:



          sw.js



          self.addEventListener('fetch', e => {
          // in this app, if a fetch event url calls the back-end, it contains api and we
          // treat it differently from the app shell

          if (!e.request.url.includes('api')) {
          switch(e.request.url) {
          case `${endpoint}/bar`: // <-- this is the problem right here
          matcher(e, '/views/bar.html');
          break;
          case `${endpoint}/bar.js`:
          matcher(e, '/scripts/bar.js');
          break;
          case `${endpoint}/index.js`:
          matcher(e, '/index.js');
          break;
          case `${endpoint}/manifest.json`:
          matcher(e, '/manifest.json');
          break;
          case `${endpoint}/baz/`:
          matcher(e, '/views/bar.html');
          break;
          case `${endpoint}/baz.js`:
          matcher(e, '/scripts/bar.js');
          break;
          default:
          console.log('default');
          matcher(e, '/index.html');
          }
          }
          });


          Matcher is the function that matches the request url with the file on the server. If the file already exists in the cache, it returns what is in the cache but if it doesn't exist in the cache, it fetches the file from the server.



          Every time the user clicks on the notification, it's supposed to take him/her to the 'bar' html view. In the switch it must be:



          case `${endpoint}/bar/`:


          and not



          case `${endpoint}/bar`:


          Even though the message-related code is still in the firebase-messaging-sw.js file, what happens is it creates a new WindowClient when the browser is in the background. That WindowClient is under the influence of sw.js, not firebase-messaging-sw.js. As a result, when the window is opened, sw.js intercepts the call and takes over from firebase-messaging-sw.js.






          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53392277%2fcant-get-custom-push-notification-event-working-in-pwa-firebase%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            After much pain and aggravation, I figured out what the problem was. It was a combination of the architecture of the app (that is, a traditional Multi-Page App) and a badly-formed url in the custom service worker, sw.js as so:



            sw.js



            self.addEventListener('fetch', e => {
            // in this app, if a fetch event url calls the back-end, it contains api and we
            // treat it differently from the app shell

            if (!e.request.url.includes('api')) {
            switch(e.request.url) {
            case `${endpoint}/bar`: // <-- this is the problem right here
            matcher(e, '/views/bar.html');
            break;
            case `${endpoint}/bar.js`:
            matcher(e, '/scripts/bar.js');
            break;
            case `${endpoint}/index.js`:
            matcher(e, '/index.js');
            break;
            case `${endpoint}/manifest.json`:
            matcher(e, '/manifest.json');
            break;
            case `${endpoint}/baz/`:
            matcher(e, '/views/bar.html');
            break;
            case `${endpoint}/baz.js`:
            matcher(e, '/scripts/bar.js');
            break;
            default:
            console.log('default');
            matcher(e, '/index.html');
            }
            }
            });


            Matcher is the function that matches the request url with the file on the server. If the file already exists in the cache, it returns what is in the cache but if it doesn't exist in the cache, it fetches the file from the server.



            Every time the user clicks on the notification, it's supposed to take him/her to the 'bar' html view. In the switch it must be:



            case `${endpoint}/bar/`:


            and not



            case `${endpoint}/bar`:


            Even though the message-related code is still in the firebase-messaging-sw.js file, what happens is it creates a new WindowClient when the browser is in the background. That WindowClient is under the influence of sw.js, not firebase-messaging-sw.js. As a result, when the window is opened, sw.js intercepts the call and takes over from firebase-messaging-sw.js.






            share|improve this answer

























              up vote
              0
              down vote













              After much pain and aggravation, I figured out what the problem was. It was a combination of the architecture of the app (that is, a traditional Multi-Page App) and a badly-formed url in the custom service worker, sw.js as so:



              sw.js



              self.addEventListener('fetch', e => {
              // in this app, if a fetch event url calls the back-end, it contains api and we
              // treat it differently from the app shell

              if (!e.request.url.includes('api')) {
              switch(e.request.url) {
              case `${endpoint}/bar`: // <-- this is the problem right here
              matcher(e, '/views/bar.html');
              break;
              case `${endpoint}/bar.js`:
              matcher(e, '/scripts/bar.js');
              break;
              case `${endpoint}/index.js`:
              matcher(e, '/index.js');
              break;
              case `${endpoint}/manifest.json`:
              matcher(e, '/manifest.json');
              break;
              case `${endpoint}/baz/`:
              matcher(e, '/views/bar.html');
              break;
              case `${endpoint}/baz.js`:
              matcher(e, '/scripts/bar.js');
              break;
              default:
              console.log('default');
              matcher(e, '/index.html');
              }
              }
              });


              Matcher is the function that matches the request url with the file on the server. If the file already exists in the cache, it returns what is in the cache but if it doesn't exist in the cache, it fetches the file from the server.



              Every time the user clicks on the notification, it's supposed to take him/her to the 'bar' html view. In the switch it must be:



              case `${endpoint}/bar/`:


              and not



              case `${endpoint}/bar`:


              Even though the message-related code is still in the firebase-messaging-sw.js file, what happens is it creates a new WindowClient when the browser is in the background. That WindowClient is under the influence of sw.js, not firebase-messaging-sw.js. As a result, when the window is opened, sw.js intercepts the call and takes over from firebase-messaging-sw.js.






              share|improve this answer























                up vote
                0
                down vote










                up vote
                0
                down vote









                After much pain and aggravation, I figured out what the problem was. It was a combination of the architecture of the app (that is, a traditional Multi-Page App) and a badly-formed url in the custom service worker, sw.js as so:



                sw.js



                self.addEventListener('fetch', e => {
                // in this app, if a fetch event url calls the back-end, it contains api and we
                // treat it differently from the app shell

                if (!e.request.url.includes('api')) {
                switch(e.request.url) {
                case `${endpoint}/bar`: // <-- this is the problem right here
                matcher(e, '/views/bar.html');
                break;
                case `${endpoint}/bar.js`:
                matcher(e, '/scripts/bar.js');
                break;
                case `${endpoint}/index.js`:
                matcher(e, '/index.js');
                break;
                case `${endpoint}/manifest.json`:
                matcher(e, '/manifest.json');
                break;
                case `${endpoint}/baz/`:
                matcher(e, '/views/bar.html');
                break;
                case `${endpoint}/baz.js`:
                matcher(e, '/scripts/bar.js');
                break;
                default:
                console.log('default');
                matcher(e, '/index.html');
                }
                }
                });


                Matcher is the function that matches the request url with the file on the server. If the file already exists in the cache, it returns what is in the cache but if it doesn't exist in the cache, it fetches the file from the server.



                Every time the user clicks on the notification, it's supposed to take him/her to the 'bar' html view. In the switch it must be:



                case `${endpoint}/bar/`:


                and not



                case `${endpoint}/bar`:


                Even though the message-related code is still in the firebase-messaging-sw.js file, what happens is it creates a new WindowClient when the browser is in the background. That WindowClient is under the influence of sw.js, not firebase-messaging-sw.js. As a result, when the window is opened, sw.js intercepts the call and takes over from firebase-messaging-sw.js.






                share|improve this answer












                After much pain and aggravation, I figured out what the problem was. It was a combination of the architecture of the app (that is, a traditional Multi-Page App) and a badly-formed url in the custom service worker, sw.js as so:



                sw.js



                self.addEventListener('fetch', e => {
                // in this app, if a fetch event url calls the back-end, it contains api and we
                // treat it differently from the app shell

                if (!e.request.url.includes('api')) {
                switch(e.request.url) {
                case `${endpoint}/bar`: // <-- this is the problem right here
                matcher(e, '/views/bar.html');
                break;
                case `${endpoint}/bar.js`:
                matcher(e, '/scripts/bar.js');
                break;
                case `${endpoint}/index.js`:
                matcher(e, '/index.js');
                break;
                case `${endpoint}/manifest.json`:
                matcher(e, '/manifest.json');
                break;
                case `${endpoint}/baz/`:
                matcher(e, '/views/bar.html');
                break;
                case `${endpoint}/baz.js`:
                matcher(e, '/scripts/bar.js');
                break;
                default:
                console.log('default');
                matcher(e, '/index.html');
                }
                }
                });


                Matcher is the function that matches the request url with the file on the server. If the file already exists in the cache, it returns what is in the cache but if it doesn't exist in the cache, it fetches the file from the server.



                Every time the user clicks on the notification, it's supposed to take him/her to the 'bar' html view. In the switch it must be:



                case `${endpoint}/bar/`:


                and not



                case `${endpoint}/bar`:


                Even though the message-related code is still in the firebase-messaging-sw.js file, what happens is it creates a new WindowClient when the browser is in the background. That WindowClient is under the influence of sw.js, not firebase-messaging-sw.js. As a result, when the window is opened, sw.js intercepts the call and takes over from firebase-messaging-sw.js.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 20 at 14:56









                Testinnplayin

                11




                11






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53392277%2fcant-get-custom-push-notification-event-working-in-pwa-firebase%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Wiesbaden

                    Marschland

                    Dieringhausen