user3030010 user3030010 - 1 month ago 47
Javascript Question

How do you retrieve notification/data from a request?

I'm trying to send a basic notification using Firebase Cloud Messaging, but I cannot for the life of me figure out how to include any actual content in the notification.

I'm starting with essentially a stripped-down version of what can be found here. I have three files, a manifest.json, which looks like this:

{ "gcm_sender_id": "my sender id" }


an index.html, which looks like this:

<html>
<head><link rel="manifest" href="manifest.json"></head>
<body>
<div id="endpoint-show">There doesn't seem to be an endpoint right now</div>

<script src="https://www.gstatic.com/firebasejs/3.5.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/3.5.0/firebase-messaging.js"></script>
<script>
var config = {apiKey: "my key", authDomain: "my domain", messagingSenderId: "my id"};
firebase.initializeApp(config);

const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() { console.log('Notification permission granted.'); })
.catch(function(err) { console.log('Unable to get permission to notify. ', err); });

navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly: true})
.then(function(subscription) {
document.getElementById("endpoint-show").innerHTML = "<p>" + subscription.endpoint.split('/\').slice(-1)[0] + "</p>";
})
});
navigator.serviceWorker.register('./service-worker.js')
</script>
</body>
<html>


and a service-worker.js, which looks like:

self.addEventListener('push', function(event) {
console.log('Received a push message', event);
event.waitUntil(self.registration.showNotification("title", { body: "body" }));
});


This seems to be about the minimum amount of code required to register a subscription for push notifications and establish a service worker to handle them.

I then send notifications using a curl command like the one shown here. Ie, POST to https://fcm.googleapis.com/fcm/send with those certain headers set and a body that contains a "too" field which is equal to the one that my idex.html shows. This works, insofar that I get a notification on my computer with the title "title" and the body "body".

But here is where I am stuck: It seems like the only data I can send through this request is the fact that a notification happens, and not any other (actual) data. The first example I linked just hard-codes a notification, as does my own code, but I would like to be able to send a request with arbitrary data. The documentation here seems to indicate that I should be able to set either the
data
or
notification
field of the request, and get a notification that has that data, but that doesn't seem to work. I have set both fields in the request I'm making, so the whole thing looks something like this (which I am sending using postman):

POST /fcm/send HTTP/1.1
Host: fcm.googleapis.com
Content-Type: application/json
Authorization: key=my key
Cache-Control: no-cache
Postman-Token: some token

{
"notification": {
"body": "notification body",
"title": "notification title"
},
"data": {
"body": "data body",
"title": "data title"
},
"to" : "my endpoint"
}


But I can't figure out how to actually retrieve any of that data. The event that my service worker captures does not contain any of this data. None of the documentation I have looked at seems to describe how to actually get this data through the web, only on Android or iOS, but obviously it is possible since many website implement dynamic notifications.

I suspect that I have some fundamental misunderstanding of how all of this works, which would not be surprising since I have very little experience with any kind of web development. If what I'm trying to do is impossible, or much be done a completely different way, let me know.

And just to reiterate, here is exactly what I am trying to do:


  1. Send a request (whether that is to a webserver that I write or to firebase).

  2. Have a notifcation pop up on my Chrome with information from that request.


Answer

You seem to be mixing the new firebase messaging lib with the old style service worker code.

After you get the permission, you need to call the getToken API.

  // service.js
  // after request permission is successful
  // Get Instance ID token. Initially this makes a network call, once retrieved
  // subsequent calls to getToken will return from cache.
  messaging.getToken()
    .then(function(currentToken) {
      if (currentToken) {
        sendTokenToServer(currentToken);
        updateUIForPushEnabled(currentToken);
      } else {
        // Show permission request.
        console.log('No Instance ID token available. Request permission to generate one.');
        // Show permission UI.
        updateUIForPushPermissionRequired();
        setTokenSentToServer(false);
      }
   })
   .catch(function(err) {
     console.log('An error occurred while retrieving token. ', err);
     showToken('Error retrieving Instance ID token. ', err);
     setTokenSentToServer(false);
   });

Its debatable, but you also need to create a service work with filename as firebase-messaging-sw.js. Reference can be found here.

And in this service worker you need to put something like this:

// firebase-messaging-sw.js
'use strict';
console.log('Starting service worker');

if( 'function' === typeof importScripts) {

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

  // Initialize the Firebase app in the service worker by passing in the
  // messagingSenderId.
  firebase.initializeApp({
    'messagingSenderId': 'YOUR-SENDER-ID'
  });

  // Retrieve an instance of Firebase Messaging so that it can handle background
  // messages.
  const messaging = firebase.messaging();


  messaging.setBackgroundMessageHandler(function(payload) {
    var shinyData = payload || {};

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

    return self.registration.showNotification(shinyData.title, {
      body: shinyData.body,
      icon: shinyData.icon,
      data: {url: shinyData.tag}
    })
  });
}

You may find this gist I created helpful.