|
|
@ -1,19 +1,19 @@ |
|
|
|
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. |
|
|
|
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.] |
|
|
|
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: |
|
|
|
|
|
|
@ -22,13 +22,18 @@ 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. |
|
|
|
The SERVICE will provide context and obtain explicit permission before prompting |
|
|
|
for notification permission: |
|
|
|
|
|
|
|
In Typescript, we can activate a browser's permission dialogue in this manner: |
|
|
|
In orer to provide this context and explict permission 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. |
|
|
|
|
|
|
|
Now, to explain what happens 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) { |
|
|
@ -45,14 +50,54 @@ function askPermission(): Promise<NotificationPermission> { |
|
|
|
return permissionResult; |
|
|
|
}); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
If the user grants permission, the client application registers a service worker |
|
|
|
using the `ServiceWorkerRegistration` API. |
|
|
|
|
|
|
|
The `ServiceWorkerRegistration` API is accessible via the browser's `navigator` |
|
|
|
object and the `navigator.serviceWorker` child object and ultimately directly |
|
|
|
accessible via the navigator.serviceWorker.register method which also creates |
|
|
|
the service worker or the navigator.serviceWorker.getRegistration method. |
|
|
|
|
|
|
|
Once you have a `ServiceWorkerRegistration` object, that object will provide a |
|
|
|
child object named `pushManager` through which subscription and management of |
|
|
|
subscriptions may be done. |
|
|
|
|
|
|
|
If the user grants permission, the client application registers a service worker using |
|
|
|
the ServiceWorkerRegistration API. |
|
|
|
Let's go through the `register` method first: |
|
|
|
|
|
|
|
``` |
|
|
|
navigator.serviceWorker.register('sw.js', { scope: '/' }) |
|
|
|
.then(function(registration) { |
|
|
|
console.log('Service worker registered successfully:', registration); |
|
|
|
}) |
|
|
|
.catch(function(error) { |
|
|
|
console.log('Service worker registration failed:', error); |
|
|
|
}); |
|
|
|
``` |
|
|
|
|
|
|
|
The `sw.js` file contains the logic for what a service worker should do. |
|
|
|
It executes in a separate thread from the web page but provides a means |
|
|
|
of communicating between itself and the web page via messages. |
|
|
|
|
|
|
|
Note that there is a scope can specify what network requests it may |
|
|
|
intercept. |
|
|
|
|
|
|
|
The Vue project already has its own service worker but it is possible to |
|
|
|
create multiple service worker files by registering them on different scopes. |
|
|
|
|
|
|
|
It is useful architecturally to specify a separate server worker. |
|
|
|
|
|
|
|
In the case of web push, the path of the scope only has reference to the domain |
|
|
|
of the service worker and no relationship to the pathing for the web push |
|
|
|
server. In order to specify different server workers they need to be on |
|
|
|
different scope paths! |
|
|
|
|
|
|
|
Here's a version which can be used for testing locally. Note there can be |
|
|
|
caching issues in your browser! Incognito is highly recommended. |
|
|
|
|
|
|
|
sw-dev.ts |
|
|
|
|
|
|
|
self.addEventListener('push', function(event: PushEvent) { |
|
|
|
console.log('Received a push message', event); |
|
|
|
|
|
|
|