Push notifications were once a feature limited to the land of native apps with direct access to their mobile hardwares sound and wake functionality. However, web push notifications for Progressive Web Apps (PWAs) have extended almost the same functionality into mobile browsers with the use of service workers. Service workers are javascript workers that are completely separate from the DOM but can do things like sync data in the background and send push notifications.
Getting web push notifications enabled for an end user, on their client side rendering, requires 3 steps.
- Permissions UI & acceptance by end user
- Subscription keys generation client side
- Send keys in a POST request to the server database
A user initiated prompt is ideal to enabled the permissions UX, versus spamming the user with the the permissions UX as soon as they visit the site. A user intimated prompt or menu UI will also prevent the user from accidentally blocking the permissions UX permanently. Allowing a end user to also enable or disable the notifications in a settings UI is also helpful to prevent the user from blocking the notifications all together when they want to temporarily disable the notifications. Before we display a notifications UI to the end user, we will want to check the browser compatibility for push notifications and if the service worker is enabled. You can do this simply by checking the navigator and window objects.
if (!('serviceWorker' in navigator)) {
// Service Worker isn't supported on this browser, disable or hide UI.
return;
}
if (!('PushManager' in window)) {
// Push isn't supported on this browser, disable or hide UI.
return;
}
If both checks pass, we can register the service worker and use the registration to utilize the Push Manager API
This is where things get slightly tricky. The Notifications permissions function used to use a callback to return the permissions UX result, however, the current spec uses a promised based syntax. The latest spec works like this:
Notification.requestPermission().then(function(permission) { ... });
Previously, the syntax was based on a simple callback:
Notification.requestPermission(callback);
The problem arises because we are unable to check the browser API version and Safari Version 12.0.3 still uses a callback to get the permission. Since the result of Notification.requestPermission
will either be granted
, default
or denied
, we can handle the result of the permissions request by handling both a callback and promise by using an arrow function within the notification request as a callback first and then utilizes a promise .then
.
function askPermission() {
const permissionResult = (permission) => {
if (permission === "granted") {
//subscribe the user
}
}
Notification.requestPermission((permission) => {
permissionResult(permission)
}).then((permission) => {
permissionResult(permission)
});
}
Once we have permission with the service worker registered, we can subscribe the user to the push notification by using the
function subscribeUser() {
const subscribeOptions = {
//userVisibleOnly must be true
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'APPLICATION_SERVER_KEY'
)
};
return registration.pushManager.subscribe(subscribeOptions).then(function(pushSubscription) {
//Save the subscription to the server
});
}