|
|
|
Web Push notifications is a web browser messaging protocol defined by the W3C.
|
|
|
|
|
|
|
|
Discussions of this interesting technology are clouded because of a terminological
|
|
|
|
morass.
|
|
|
|
|
|
|
|
To understand how Web Push operates, we need to observe that are three (and
|
|
|
|
potentially four) parties involved. These are:
|
|
|
|
|
|
|
|
1) The user's web browser. Let's call that BROWSER
|
|
|
|
2) The Web Push Service Provider which is operated by the organization controlling the
|
|
|
|
web browser's source code. Here named PROVIDER. An example of a PROVIDER is
|
|
|
|
FCM (Firebase Cloud Messaging) which is owned by Google.
|
|
|
|
3) The Web Application that a user is visiting from their web browser. Let's call this the
|
|
|
|
SERVICE (short for Web Push application service)
|
|
|
|
[4) A Custom Web Push Intermediary Service, either third party or self-hosted. Called
|
|
|
|
INTERMEDIARY here.]
|
|
|
|
|
|
|
|
The workflow works like this:
|
|
|
|
|
|
|
|
BROWSER visits a website which has a SERVICE.
|
|
|
|
|
|
|
|
The SERVICE asks BROWSER for its permission to subscribe to messages coming
|
|
|
|
from the SERVICE.
|
|
|
|
|
|
|
|
Provide context and obtain explicit permission before prompting for notification permission:
|
|
|
|
It is recommended to set up to a two-step opt-in process where the user is first presented
|
|
|
|
with a pre-permission dialog box that explains what the notifications are for and why they
|
|
|
|
are useful. This may help reduce the possibility of users clicking "don't allow.
|
|
|
|
|
|
|
|
In Typescript, we can activate a browser's permission dialogue in this manner:
|
|
|
|
|
|
|
|
function askPermission(): Promise<NotificationPermission> {
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
const permissionResult = Notification.requestPermission(function(result) {
|
|
|
|
resolve(result);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (permissionResult) {
|
|
|
|
permissionResult.then(resolve, reject);
|
|
|
|
}
|
|
|
|
}).then(function(permissionResult) {
|
|
|
|
if (permissionResult !== 'granted') {
|
|
|
|
throw new Error("We weren't granted permission.");
|
|
|
|
}
|
|
|
|
return permissionResult;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
If the user grants permission, the client application registers a service worker using
|
|
|
|
the ServiceWorkerRegistration API.
|
|
|
|
|
|
|
|
|
|
|
|
Here's a version which can be used for testing locally. Note there can be
|
|
|
|
caching issues in your browser! Incognito is highly recommended.
|
|
|
|
|
|
|
|
self.addEventListener('push', function(event: PushEvent) {
|
|
|
|
console.log('Received a push message', event);
|
|
|
|
|
|
|
|
const title = 'Push message';
|
|
|
|
const body = 'The message body';
|
|
|
|
const icon = '/images/icon-192x192.png';
|
|
|
|
const tag = 'simple-push-demo-notification-tag';
|
|
|
|
|
|
|
|
event.waitUntil(
|
|
|
|
self.registration.showNotification(title, {
|
|
|
|
body: body,
|
|
|
|
icon: icon,
|
|
|
|
tag: tag
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
vue.config.js
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
pwa: {
|
|
|
|
workboxOptions: {
|
|
|
|
importScripts: ['sw-dev.ts']
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
In the next step, BROWSER requests a data structure from SERVICE called a VAPID (Voluntary
|
|
|
|
Application Server Identification) which is the public key from a key-pair.
|
|
|
|
|
|
|
|
The VAPID is a specification used to identify the application server (i.e. the SERVICE
|
|
|
|
server) that is sending push messages to a push service. It's an authentication
|
|
|
|
mechanism that allows the server to demonstrate its identity to the push service, by use
|
|
|
|
of a public and private key pair. These keys are used by the SERVICE in encrypting
|
|
|
|
messages being sent to the BROWSER, as well as being used by the BROWSER in
|
|
|
|
decrypting the messages coming from the SERVICE.
|
|
|
|
|
|
|
|
If the BROWSER accepts and grants permission to subscribe to receiving from the
|
|
|
|
SERVICE Web Push messages, then the BROWSER makes a subscription request to
|
|
|
|
PROVIDER which creates and stores a special URL for that BROWSER.
|
|
|
|
|
|
|
|
const applicationServerKey = urlBase64ToUint8Array('BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U');
|
|
|
|
const options: PushSubscriptionOptions = {
|
|
|
|
userVisibleOnly: true,
|
|
|
|
applicationServerKey: applicationServerKey
|
|
|
|
};
|
|
|
|
|
|
|
|
registration.pushManager.subscribe(options)
|
|
|
|
.then(function(subscription) {
|
|
|
|
console.log('Push subscription successful:', subscription);
|
|
|
|
})
|
|
|
|
.catch(function(error) {
|
|
|
|
console.error('Push subscription failed:', error);
|
|
|
|
});
|
|
|
|
|
|
|
|
In this example, the `applicationServerKey` variable contains the VAPID public key,
|
|
|
|
which is converted to a Uint8Array using the `urlBase64ToUint8Array()` function from the
|
|
|
|
convert-vapid-public-key package. The options object is of type PushSubscriptionOptions,
|
|
|
|
which includes the `userVisibleOnly` and `applicationServerKey` (ie VAPID public key)
|
|
|
|
properties. The subscribe() method returns a `Promise` that resolves to a `PushSubscription`
|
|
|
|
object containing details of the subscription, such as the endpoint URL and the public key.
|
|
|
|
|
|
|
|
The VAPID (Voluntary Application Server Identification) key provides more security and
|
|
|
|
authenticity for web push notifications in the following ways:
|
|
|
|
|
|
|
|
Identifying the Application Server:
|
|
|
|
|
|
|
|
The VAPID key is used to identify the application server that is sending the push notifications.
|
|
|
|
This ensures that the push notifications are authentic and not sent by a malicious third party.
|
|
|
|
|
|
|
|
Encrypting the Messages:
|
|
|
|
|
|
|
|
The VAPID key is used to sign the push notifications sent by the application server,
|
|
|
|
ensuring that they are not tampered with during transmission. This provides an additional
|
|
|
|
layer of security and authenticity for the push notifications.
|
|
|
|
|
|
|
|
Adding Contact Information:
|
|
|
|
|
|
|
|
The VAPID key allows a web application to add contact information to the push messages sent to the browser push service.
|
|
|
|
This enables the push service to contact the application server in case of need or provide additional debug information about the push messages.
|
|
|
|
|
|
|
|
Improving Delivery Rates:
|
|
|
|
|
|
|
|
Using the VAPID key can help improve the overall performance of web push notifications, specifically improving delivery rates.
|
|
|
|
By streamlining the delivery process, the chance of delivery errors along the way is lessened.
|
|
|
|
|
|
|
|
|
|
|
|
The PROVIDER sends this URL back to the BROWSER. The BROWSER will then use that
|
|
|
|
URL to check for incoming messages by way of a special software named a "service
|
|
|
|
worker". The BROWSER also sends this URL back to SERVICE which will use that
|
|
|
|
URL to send messages to the BROWSER via the PROVIDER.
|
|
|
|
|
|
|
|
Ultimately, the actual process of receiving messages varies from BROWSER to
|
|
|
|
BROWSER. Approaches vary from long-polling HTTP connections to WebSockets. A
|
|
|
|
lot of handwaving and voodoo magic. The bottom line is that the BROWSER itself
|
|
|
|
manages the connection to the PROVIDER whilst the SERVICE must send messages
|
|
|
|
via the PROVIDER so that they reach the BROWSER.
|
|
|
|
|
|
|
|
Now to address the issue of receiving notification messages on mobile devices.
|
|
|
|
It should be noted that Web Push messages are only received when BROWSER is
|
|
|
|
open, except in the cases of Chrome and Firefox mobile BROWSERS. In iOS the
|
|
|
|
mobile application (in our case a PWA) must be added to the Home Screen and
|
|
|
|
permissions must be explicitly granted that allow the application to receive push
|
|
|
|
notifications. Further, with an iOS device the user must enable wake on notification to
|
|
|
|
have their device light-up when it receives a notification (https://support.apple.com/enus/HT208081).
|
|
|
|
|
|
|
|
So what about #4? - The INTERMEDIARY. Well, It is possible under very special
|
|
|
|
circumstances to create your own Web Push PROVIDER. The only case I've found so
|
|
|
|
far relates to making an Android Custom ROM. (An Android Custom ROM is a
|
|
|
|
customized version of the Android Operating System.) There are open source
|
|
|
|
IMTERMEDIARY products such as UnifiedPush (https://unifiedpush.org/) which can
|
|
|
|
fulfill this role. If you are using iOS you are not permitted to make or use your own
|
|
|
|
custom Web Push PROVIDER. Apple will never allow anyone to do that. Apple has
|
|
|
|
none of its own.
|
|
|
|
|
|
|
|
It is, however, possible to have a sort of proxy working between your SERVICE and
|
|
|
|
FCM (or iOS). Services that mash up various Push notification services (like
|
|
|
|
OneSignal) can perform in the role of such proxies.
|
|
|
|
|
|
|
|
#4 -The INTERMEDIARY- doesn't appear to be anything we should be spending our
|
|
|
|
time on.
|