firebase / quickstart-js

Firebase Quickstart Samples for Web
https://firebase.google.com
Apache License 2.0
5.1k stars 3.66k forks source link

Background Notification in PWA angular don't work (macOs and windows) #410

Open geeksha opened 4 years ago

geeksha commented 4 years ago

I was implementing Firebase notifications in one angular app, multicast ones. They worked really well in foreground in all the operative systems, unless in Safari browser in Mac (in chrome worked well in Mac too).

However, background notifications are working with the expected behavior in Linux OS (they appear and they are clicable), but in windows they worked but are not clicable. And in mac they don't appear at all.

What is the problem? How can I get the same behavior in Windows and Mac?

jhuleatt commented 4 years ago

Hi @geeksha, FCM requires the Push API but Safari doesn't support it, so FCM won't work on Safari.

As for background notifications not being clickable, please see the docs to see the different handlers required for different app states. If it still isn't working, can you please share your sample message handling code and the request that you send to FCM servers to help us debug?

geeksha commented 4 years ago

I am following that docs. I was implementing FCM before, but right now I am doing in an angular 8 app. Here my firebase-messaging-sw.js file where I am managing background notifications, which work ok in Linux OS systems. They appear but are not clicable in windows and they don't appear in Mac.

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

firebase.initializeApp({
  'messagingSenderId': ''
});

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {

  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  var data = payload.data;
  console.log(data.type);

  // Customize notification here
    const notificationTitle = 'Invitació a taller grupal';
    const notificationOptions = {
        body: 'http://localhost:4200/room/' + data.roomName,
        icon: 'logo.png',
    requireInteraction: true,
    };

    return self.registration.showNotification(notificationTitle,
        notificationOptions);

});

My notify.js controller in node using firebase-admin SDK. I was deleting the sensitive data about private key etc to paste here:

var mongoose = require('mongoose');
var User = mongoose.model('User');
/* CONFIGURATION Firebase */

var fb_admin = require('firebase-admin');
var config = {
    serverKey: "",
    privateKeyFile: "",
    databaseURL: ""
};

fb_admin.initializeApp({
    credential: fb_admin.credential.cert(config.privateKeyFile),
    databaseURL: config.databaseURL
});

module.exports.notify = function(req,res){

       // These registration tokens come from the client FCM SDKs.
const notifTokens = req.body.notifTokens;

//These roomName too
  const roomName = req.body.roomName;

  const fcm_message = {
    data: {
      roomName:roomName
    },
    tokens: notifTokens,
  }

  fb_admin.messaging().sendMulticast(fcm_message)
    .then((response) => {
      if (response.failureCount > 0) {
        const failedTokens = [];
        response.responses.forEach((resp, idx) => {
          if (!resp.success) {
            failedTokens.push(notifTokens[idx]);
          }
        });
        console.log('List of tokens that caused failures: ' + failedTokens);
        res.status(200).send();
      }
    });
}
geeksha commented 4 years ago

I am not pasting foreground notifications code but they work ok in all operative systems in all browsers unless Safari and you already explained the reason. The only thing regarding to foreground notifications is that sometimes happens that notifications are lost without following any specific pattern. What is exactly the multicast behavior? Is it normal that fail sometimes because of fcm part?

Thanks for the answer

geeksha commented 4 years ago
importScripts('https://www.gstatic.com/firebasejs/5.5.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/5.5.0/firebase-messaging.js');

firebase.initializeApp({
  'messagingSenderId': '407709572181'
});

const messaging = firebase.messaging();

self.addEventListener('notificationclick', function(event) {
  event.notification.close(); // Android needs explicit close.
  event.waitUntil(
      clients.matchAll({type: 'window'}).then( windowClients => {
      let url = 'https://hl4devel.i2cat.net/room/' + event.notification.data.roomName;
          // 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(url);
              }
          }
          // If not, then open the target URL in a new window/tab.
          if (clients.openWindow) {
              return clients.openWindow(url);
          }
      })
  );
});

messaging.setBackgroundMessageHandler(function(payload) {

  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  var data = payload.data;

  // Customize notification here
    const notificationTitle = 'Invitació a taller grupal';
    const notificationOptions = {
        body: 'https://hl4devel.i2cat.net/room/' + data.roomName,
        icon: 'i2cat-logo.png',
    requireInteraction: true,
    };

    return self.registration.showNotification(notificationTitle,
        notificationOptions);
});

I was updating my code trying to get the notificationclick event in Windows. It continue to work nice in linux. What I was realizing is that an static URL is working in notificationclick event, but not the custom one with the roomName variable from the data payload. This is normal??? Looks completely like a bug. It is a real problem for my application that foreground notifications works but background notification with notificationclick event only works in linux :( The docs are not preventing about this.

jhuleatt commented 4 years ago

@geeksha I noticed that you're pulling in a very old version of the firebase sdk - 5.5.0 in your code. Can you please try running a fresh clone of the current quickstart code (which today is on 7.7.0) following these steps, and see if the problem persists? I think this should resolve it.

geeksha commented 4 years ago

thanks for the answer @jhuleatt . Updating to 7.7.0 stopped to work completely the notifications. I include all my firebase config (projectId, etc,etc) generated in firebase console as I was including before, but it complaint. I need to generate another firebase config to update the sdk scripts import???

jhuleatt commented 4 years ago

What was the error? Maybe you need to register a web app in your project?

geeksha commented 4 years ago

I have already register a webapp with apiKey, authDomain, databaseURL, projectId, storageBucket, messagingSenderId and appId. So, I only changed the SDK version in the firebase scripts import. But, browser's console is giving me errors as: Error: Messaging: Missing App configuration value: "projectId" (messaging/missing-app-config-values).TypeError: ServiceWorker script at https://domain/firebase-messaging-sw.js for scope https://domain/firebase-cloud-messaging-push-scope encountered an error during installation.

The thing is that there is already a projectId. Maybe I need to register a new webapp to be able to update the firebase SDK.

jhuleatt commented 4 years ago

One other thing to try in your current code is to make sure you're passing the full firebase config.

Since this repository is focused on the quickstart, can you please try running a new project from scratch following the FCM quickstart instructions and see if you can reproduce any of the original issues? Otherwise it will be hard to track down the cause.

geeksha commented 4 years ago

I uploaded here the screenshots with the error (firefox and chrome) after registering a new web-app in an existent project and include the firebaseConfig with 7.7.0 scripts in my devel environment. My production environment is not giving this error with 5.5.0 scripts. I will try now creating a new project and registering a new web-app there to track down the cause because it's really strange.

FirebaseErrorChromeUpdated FirebaseErrorUpdated

I need to clarify that I was using fcm and firebase-js-SDK in another projects without any problem.

geeksha commented 4 years ago

Ok, I was creating a new project, registering a new web-app and it works. It was necessary to do in this way to upgrade my firebase version. So, I test the backgrounds notifications in linux: they work ok, like with the previous version) and in windows: they don't appear, so work worse than in the previous version. They appeared before, but they were not clicable.

Any another idea? I am really surprised for this behaviour. I never found it before. It's the first time that I use the firebase-js-sdk in angular context, but anyway...

jhuleatt commented 4 years ago

@geeksha can you please confirm that you're using the exact code that's in the quickstart repo (without angular or any other libraries or custom code)? Any error messages you're seeing when you load the site in the browser?

geeksha commented 4 years ago

@jhuleatt I was missing this answer, sorry. I can confirm that I have the exact code in firebase-messaging-sw.js that's in quickstart repo. No errors loading the site. I can check if windows user has dome errors when they are not receiving the background notification. Linux users get it without any problem.

geeksha commented 4 years ago

@jhuleatt NoError There is not error in console, but background notifications works in linux and not in windows with the 7.7.0 version and the exact code from the quick-start repo for my app.

echofrost38 commented 4 years ago

geeksha, Hi. I have also issue in background push notification implementation. when browser is opened with home url, push notification working well. This status is forground. Btw when the app is closed, and haven't any url on browser, I get push notification twice. If you have already this issue and experience in this, please help me. Thanks

geeksha commented 4 years ago

Push notification twice, this was not happening to me, sorry!!

Suketu-Patel commented 3 years ago

@geeksha Hope this helps. ( Works in firefox and chrome on MacOSX Catalina 10.15.2 ) @timeworn I faced that exact issue. The below code is a workaround for that.

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

//Ignore this part if you are not using ReactJS
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./firebase-messaging-sw.js').then(function (reg) {
        console.log('reg: ', reg.scope);
    }).catch(function (err) {
        console.log('err: ', err);
    })
}

//place your config here
firebase.initializeApp({
    messagingSenderId: 123465,
    projectId: "",
    apiKey: "",
    appId: ""
});

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

        Object.assign(this, data)
        this.custom = true
    }
}

/*
 * Overrides push notification data, to avoid having 'notification' key and firebase blocking
 * the message handler from being called
 */
self.addEventListener('push', (e) => {
    // Skip if event is our own custom event
    if (e.custom) return;

    // Kep old event data to override
    let oldData = e.data

    // Create a new event to dispatch, pull values from notification key and put it in data key, 
    // and then remove notification key
    let newEvent = new CustomPushEvent({
        data: {
            json() {
                let newData = oldData.json()
                newData.data = {
                    ...newData.data,
                    ...newData.notification
                }
                delete newData.notification
                return newData
            },
        },
        waitUntil: e.waitUntil.bind(e),
    })

    // Stop event propagation
    e.stopImmediatePropagation()

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

const messaging = firebase.messaging();

messaging.onBackgroundMessage(function (payload) {
    const notificationTitle = payload.data.title;
    const notificationOptions = {
        body: payload.data.body,
        icon: payload.data.icon,
        data: payload.data
    };
    return self.registration.showNotification(notificationTitle,
        notificationOptions);
});

self.onnotificationclick = function (event) {
    //Place your on click logic here

    //example
    const endpoint = event.notification.data.type;
    self.clients.openWindow('/' + endpoint || "")
    event.notification.close()
}
sambecker commented 3 years ago

@Suketu-Patel this helped me so much! Amazing this can't be handled through Firebase's Messaging API.