25

I am implementing the Webpush ruby gem to send push notifications to users of my website.

Server code:

  Webpush.payload_send({
      message: notification.message,
      url: notification.url,  # I can't figure out how to access this key
      id: notification.id,    # or this key from the service worker
      endpoint: endpoint,
      p256dh: p256dh_key,
      vapid: vapid_keys,
      ttl: 24 * 60 * 60,
      auth: auth_key,
    })

I have a service worker set up on the client side to show the notification and make it clickable.

self.addEventListener("push", function (event) {
  var title = (event.data && event.data.text()) || "New Message";

  event.waitUntil(
    self.registration.showNotification(title, {
      body: "New push notification",
      icon: "/images/logo@2x.png",
      tag:  "push-notification-tag",
      data: {
        url: event.data.url, // This is returning null
        id: event.data.id // And this is returning null
      }
    })
  )
});

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
    clients.openWindow(event.data.url + "?notification_id=" + event.data.id)
  );
})

It is all working fine, except the custom keys (url, id) that I am passing through are not accessible from within the service worker.

Does anyone know how to pass custom data through the WebPush gem?

BananaNeil
  • 10,322
  • 7
  • 46
  • 66
  • 1
    im not an expert in this, but i would do: message: JSON.stringify(notification) on the server, and JSON.parse on the client... – Jonas Wilms May 15 '17 at 18:55
  • @Jonasw - I ended up going with your solution. If you write it as an answer, I'll accept it. Thanks for the help. – BananaNeil May 17 '17 at 07:11

4 Answers4

25

From the Webpush (with a payload) documentation, it seems that you should put all your data into the message, using the JSON.stringify() method, and retrieve it in the service worker with JSON.parse().

Server:

Webpush.payload_send({
  message:JSON.stringify({
    message: notification.message,
    url: notification.url,
    id: notification.id,
  }),
  endpoint: endpoint,
  p256dh: p256dh_key,
  vapid: vapid_keys,
  ttl: 24 * 60 * 60,
  auth: auth_key,
})

Client:

 event.waitUntil(
   self.registration.showNotification(title, {
   body: "New push notification",
   icon: "/images/logo@2x.png",
   tag:  "push-notification-tag",
   data: {
     url: JSON.parse(event.message).url
   }
})
BananaNeil
  • 10,322
  • 7
  • 46
  • 66
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
21

Custom data comes in event.notification object not in event directly(in notificationclick). So if you want to fetch the custom data variable in notificationclick function, then you should do it like this :)

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
    clients.openWindow(event.notification.data.url + "?notification_id=" + event.notification.data.id)
  );
})
munjal
  • 1,384
  • 9
  • 15
  • 2
    The problem was receiving the data from the push event, not from the click event. But you are correct, that was another bug that I ended up needing to fix. – BananaNeil Jun 06 '17 at 23:22
  • @BananaNeil can you please mention how did you fix this "The problem was receiving the data from the push event, not from the click event." because i am also not able to send data from the server side to the client side... – Muhammad Usama Mashkoor Oct 01 '19 at 09:44
  • @usama Take a look at the accepted answer, it has the server/client code – BananaNeil Dec 05 '19 at 08:32
3

For Webpush Ruby Gem, with some modifications, here's what worked for me:

Webpush.payload_send(
  endpoint: user.push_subscription.endpoint,
  message: {
    message: "A new service request is created",
    id: service_request.request_number,
    url: "https://google.com/"
  }.to_json,
  p256dh: user.push_subscription.key,
  auth: user.push_subscription.auth_key,
  ttl: 24 * 60 * 60,
  vapid: {
    subject: 'A Push Notification',
    public_key: ENV['VAPID_PUBLIC_KEY'],
    private_key: ENV['VAPID_PRIVATE_KEY']
  }
)

Where:

  • user.push_subscription.endpoint is a method defined in PushSubscription model to return the endpoint
  • user.push_subscription.key, user.push_subscription.auth_key are again methods defined in the same model

Inside /serviceworker.js.erb

self.addEventListener("push", (event) => {
  let response = event.data && event.data.text();
  let title = JSON.parse(response).message;
  let body = JSON.parse(response).id;
  let icon = '/assets/logo-blue-120x120.jpg';

  event.waitUntil(
    self.registration.showNotification(title, { body, icon, data: { url: JSON.parse(response).url } })
  )
});

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
    clients.openWindow(event.notification.data.url)
  );
});
Puneet Pandey
  • 541
  • 2
  • 6
  • 23
0

Add this on your Angular project inside the node_modules/@angular/service-worker/ngsw-worker.js

this.scope.addEventListener('notificationclick', (event) => {
            console.log('[Service Worker] Notification click Received. event:%s', event);
            event.notification.close();
            if (clients.openWindow && event.notification.data.url) {
                event.waitUntil(clients.openWindow(event.notification.data.url));
            }
        });

You can enter the above code where you can find this line inside the file

this.scope.addEventListener('notificationclick', (event) => ..

And you have to build the dist again for this to work. And in backend you would need to use this format:

{"notification":{"body":"This is a message.","title":"PUSH MESSAGE","vibrate":[300,100,400,100,400,100,400],"icon":"https://upload.wikimedia.org/wikipedia/en/thumb/3/34/AlthepalHappyface.svg/256px-AlthepalHappyface.svg.png","tag":"push demo","requireInteraction":true,"renotify":true,"data":{"url":"https://maps.google.com"}}}

Inside the url you can enter your url and on clicking notification your push notification will open the given link and focus it in the browser

cyperpunk
  • 664
  • 7
  • 13