Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

messaging.onMessage() (JavaScript) not being called when push notification is sent

i found a question similar to that on Stackoverflow but unfortunately it wasn't answered.

I'm trying to send a push notification to Web using FCM. I have set my app server and its working fine when i put the tokens of android devices and notifications are successfully delivered to all the tokens. However, the onMessage() function on the web is not being called when the notification is sent to the web.

My code is:

<script src="https://www.gstatic.com/firebasejs/4.6.0/firebase.js"></script>
       <script>
         // Initialize Firebase
         var config = {
           apiKey: "xxxxxxxxx",
           authDomain: "xxxxxxxx",
           databaseURL: "xxxxxxx",
           projectId: "xxxxxxxxxxxx",
           storageBucket: "xxxxxxxxx",
           messagingSenderId: "xxxxxxxxx"
         };
         firebase.initializeApp(config);

           //Get Token
          const messaging = firebase.messaging();
          messaging.requestPermission()
           .then(function () {
               console.log('Have permission');
               return messaging.getToken();
           })
        .then(function (token) {
            console.log(token);
        })
          .catch(function (err) {
              console.log('Error occurred');
          });

          messaging.onMessage(function (payload) {
              console.log('onMessage', payload);
          })

Code for firebase-messaging-sw.js code:

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

var config = {
apiKey: "xxxxxxxxx",
authDomain: "XXXXXXXXXX",
databaseURL: "XXXXXXXXXX",
projectId: "XXXXXXXXXX",
storageBucket: "XXXXXXXXX",
messagingSenderId: "XXXXXXXXXX"
};

firebase.initializeApp(config);

const messaging = firebase.messaging();

I can't figure out what's wrong.

like image 647
Sinan Noureddine Avatar asked Nov 03 '17 14:11

Sinan Noureddine


1 Answers

I found this topic to be so poorly documented when I was trying to get started that I almost gave up a few times, so hopefully other people reading this may find this useful.

The whole concept of push notifications is made more confusing because there are actually different web APIs involved which work together and this is often not made clear. Then there is the debate over should you use VAPID or FCM? How about VAPID with FCM? Blah blah blah.

So, first off you need to handle checking / getting user permission for notifications, creating / updating the subscription, saving the token etc. If you are getting a token / subscription then you are all set to send data to the client (this is Push API stuff).

Technically this is all you need if your users never leave your website, but obviously they will so this is why you need a service worker. The service worker can receive your push data without the user having your site open and then do something with it. (This is Push/Service Worker API crossover).

Finally you want your users to see whatever you sent them a message about, right? The Push API gets your message data to your service worker but you still have to handle that data. You probably want to display a notification, so you need the Notification API.

Now, looking at your code you seem to be doing the first part in your front end and getting a token for your users but your service worker contains literally no code, so it does nothing. I know Firebase has some custom event handlers, but standard web push ones should work too.

All you need to get started is a basic handler for push events in your service worker code, like this:

self.addEventListener('push', function(event) {
    const push = event.data.json();
    const title = push.data.title;
    const options = JSON.parse(push.data.options);
    event.waitUntil(registration.showNotification(title, options));
});

The nice thing about this is by keeping the code simple and not hard coding any of the options for the notification within your service worker it allows your server side code to customise the behaviour and appearance of each notification on the fly. The service worker is literally just parsing the JSON input of your push payload and creating a notification using the options within the payload

You can find lists of the available options for the Notification API here, they are still changing but as of now the following PHP example in conjunction with the service worker code above will send a fairly fully featured notification via Firebase:

$push['to'] = $SUBSCRIBED-FCM-TOKEN;
$push['data']['title'] = 'Here is my title';
$push['data']['options']['body'] = 'and here is the body message';
$push['data']['options']['badge'] = '/images/chaticon.png';
$push['data']['options']['requireInteraction'] = true;
$push['data']['options']['tag'] = 'notification-tag';
$push['data']['options']['icon'] = '/images/icons/256.jpg';
$push['data']['options']['vibrate'] = array(500,150,500,150,500);
$push['data']['options']['image'] = '/images/logo.jpg';
$push['data']['options']['actions'] = array(array('action' => 'accept-action', 'title' => 'Yes', 'icon' => '/images/icons/yes.jpg' ), array('action' => 'reject-action', 'title' => 'No', 'icon' => '/images/icons/no.jpg'));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://fcm.googleapis.com/fcm/send");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($push));
curl_setopt($ch, CURLOPT_POST, 1);
$headers = array();
$headers[] = "Content-Type: application/json";
$headers[] = "Authorization: key=$SERVER-KEY-FROM-FIREBASE-CONSOLE";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close ($ch);

Obviously this is just a basic example to get you going, you may choose to add fetch events in response to clicks on your notification actions etc to perform further actions, for analytics or whatever. You can also alter the behaviour based upon whether the user is already on your site or not.

like image 81
miknik Avatar answered Oct 15 '22 00:10

miknik