First, I would recommend you read (or skim) the Google Developers post on Push Notifications on Google Chrome. The following are a few excerpts that caught my eye:
See also:
I set up the web project I was working on to receive push notifications using a service worker much like the examples in the post. One key difference; Instead of the following push event handler:
I instead chose to try:
I did this to test the consequences and see what would happen. As I more or less expected by this point, I saw some output in the console indicating I had received a push message, but I did see any notification pop up. Interesting...
I decided to test this further. I then modified the code to be the following:
In the JavaScript console of my webpage, I experimented with setting the value of window.globalBoolean to true or false. Much to my amazement, the code (which, mind you, is in a ServiceWorker.js file running in the background) picked up on it! It would show push notifications when I set the globalBoolean to true, and stop showing them once I set them to false. However, as a fascinating caveat, I found that once I refreshed the webpage, setting globalBoolean no longer had any effect on the service worker displaying notifications; it was simply stuck to whatever I set it to prior to refreshing. Weird!
By this point I was very invested. I decided to do a little research on how to communicate from my webpage to my service worker, and I discovered there's actually a pretty simple little protocol for doing so. I modified my service worker code one last time to:
You’ll notice that we show a notification even when there is an error. This is because if we don’t, Chrome will show it’s own generic notification.
See also:
When can I use push without showing notifications (i.e. silent background push)?
There is no timeline for when this will be available yet, but there is an intent to implement background syncand while it’s not decided or spec’d, there is some discussion of enabling silent push with background sync.And under the limitations section:
you have to show a notification when you receive a push messageAt the time I first experimented with the Push API for Google Chrome, the first quote wasn't in the blog post, though the second two were. Being a naturally inquisitive creature, I wondered why you had to show a notifications, and more specifically, what were the consequences of not doing so. For a project I happened to be working on, I wanted to show push notifications when the site was in the background or closed, but obviously not when the user was browsing the website, as that would be annoying. So I experimented.
I set up the web project I was working on to receive push notifications using a service worker much like the examples in the post. One key difference; Instead of the following push event handler:
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
var title = 'Yay a message.';
var body = 'We have received a push message.';
var icon = '/images/icon-192x192.png';
var tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
});
I instead chose to try:
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
var title = 'Yay a message.';
var body = 'We have received a push message.';
var icon = '/images/icon-192x192.png';
var tag = 'simple-push-demo-notification-tag';
//event.waitUntil(
// self.registration.showNotification(title, {
// body: body,
// icon: icon,
// tag: tag
// })
//);
});
I did this to test the consequences and see what would happen. As I more or less expected by this point, I saw some output in the console indicating I had received a push message, but I did see any notification pop up. Interesting...
I decided to test this further. I then modified the code to be the following:
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
var title = 'Yay a message.';
var body = 'We have received a push message.';
var icon = '/images/icon-192x192.png';
var tag = 'simple-push-demo-notification-tag';
if(window.globalBoolean) {
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
}
});
In the JavaScript console of my webpage, I experimented with setting the value of window.globalBoolean to true or false. Much to my amazement, the code (which, mind you, is in a ServiceWorker.js file running in the background) picked up on it! It would show push notifications when I set the globalBoolean to true, and stop showing them once I set them to false. However, as a fascinating caveat, I found that once I refreshed the webpage, setting globalBoolean no longer had any effect on the service worker displaying notifications; it was simply stuck to whatever I set it to prior to refreshing. Weird!
By this point I was very invested. I decided to do a little research on how to communicate from my webpage to my service worker, and I discovered there's actually a pretty simple little protocol for doing so. I modified my service worker code one last time to:
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
var title = 'Yay a message.';
var body = 'We have received a push message.';
var icon = '/images/icon-192x192.png';
var tag = 'simple-push-demo-notification-tag';
if(self.showNotifications) {
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
}
});
Additionally, I added the following to my service worker as well:
self.showNotifications = false; //default value
//listen for messages
self.addEventListener('message', function(event) {
self.showNotifications = event.data === "true";
});
As you might imagine, this piece of code listens for a message event; when it receives a message, if the data contains the string "true", it sets self.showNotifications to true, otherwise it sets self.showNotifications to false. Not exactly the greatest code, but a good place to start experimenting.
To my front-end client, I added the following function:
function turnPushNotificationsOn() {
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
// This wraps the message posting/response in a promise, which will resolve if the response doesn't
// contain an error, and reject with the error if it does. If you'd prefer, it's possible to call
// controller.postMessage() and set up the onmessage handler independently of a promise, but this is
// a convenient wrapper.
return new Promise(function(resolve, reject) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
if (event.data.error) {
reject(event.data.error);
} else {
resolve(event.data);
}
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage("true", [messageChannel.port2]);
});
}
}
I borrowed much of the above code from an example I found online for how to send messages to your service worker from your front end. I repurposed it specifically to send a "true" message to the service worker when turnPushNotificationsOn() was called.
Sure enough, I found that because I set self.showNotifications to false by default, notifications were arriving but not displaying. Once I called my new client function, self.showNotifications was set to true, and notifications would start displaying. This setting persisted until I turned it off again (using a function similar to turnPushNotificationsOn, but which I won't include here because duh), and the functions would even work across page refreshes. I had my solution!
Is this a bug? Maybe. Is it hacky? Yeah, kinda. But does it work? Up until Chrome 48, the answer is yes. There is no consequence to doing this as far as I've been able to tell on Chrome for Windows, Mac, or Android. In the example I showed, all I did was use this to control whether push notifications were shown or not. I needed this for a project because I did not want push notifications to display while the user was on the site. While not showing push notifications for active apps is a given behavior on mobile operating systems, the same cannot be said for the web (yet). Needless to say, if that were the case, I would not have had to come up with this solution. I was able to use the above solution in conjunction with some handy event listeners like "visibilitychange" and "beforeunload" to only turn push notifications on when the site was in the background or closed.
Push Notifications on web are a very young technology, and I'm very interested in seeing where they go, even if their behavior isn't quite there yet. That said, I did very much enjoy piecing together my own solution, and I hope this is helpful for any of you working on similar projects.
Comments
Post a Comment
Leave your comment here.
Remember to be respectful to others!