Skip to content

Commit e7f339f

Browse files
committed
Support pushsubscriptionchange event in service worker. Resolves #8
1 parent 6678522 commit e7f339f

File tree

4 files changed

+94
-45
lines changed

4 files changed

+94
-45
lines changed

Demo.AspNetCore.PushNotifications/wwwroot/push-notifications.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<button id="clear" style="position: relative; top: 3px;">Clear</button>
3030
</div>
3131
</div>
32+
<script src="scripts/push-notifications-controller.js"></script>
3233
<script src="scripts/push-notifications.js"></script>
3334
</body>
3435
</html>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const PushNotificationsController = (function () {
2+
function urlB64ToUint8Array(base64String) {
3+
const padding = '='.repeat((4 - base64String.length % 4) % 4);
4+
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
5+
6+
const rawData = window.atob(base64);
7+
const outputArray = new Uint8Array(rawData.length);
8+
9+
for (let i = 0; i < rawData.length; ++i) {
10+
outputArray[i] = rawData.charCodeAt(i);
11+
}
12+
13+
return outputArray;
14+
}
15+
16+
return {
17+
retrievePublicKey: function () {
18+
return fetch('push-notifications-api/public-key').then(function (response) {
19+
if (response.ok) {
20+
return response.text().then(function (applicationServerPublicKeyBase64) {
21+
return urlB64ToUint8Array(applicationServerPublicKeyBase64);
22+
});
23+
} else {
24+
return Promise.reject(response.status + ' ' + response.statusText);
25+
}
26+
});
27+
},
28+
storePushSubscription: function (pushSubscription) {
29+
return fetch('push-notifications-api/subscriptions', {
30+
method: 'POST',
31+
headers: { 'Content-Type': 'application/json' },
32+
body: JSON.stringify(pushSubscription)
33+
});
34+
},
35+
discardPushSubscription: function (pushSubscription) {
36+
return fetch('push-notifications-api/subscriptions?endpoint=' + encodeURIComponent(pushSubscription.endpoint), {
37+
method: 'DELETE'
38+
});
39+
}
40+
};
41+
})();

Demo.AspNetCore.PushNotifications/wwwroot/scripts/push-notifications.js

Lines changed: 18 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,29 @@
1-
var PushNotifications = (function () {
1+
const PushNotifications = (function () {
22
let applicationServerPublicKey;
33

44
let consoleOutput;
55
let pushServiceWorkerRegistration;
66
let subscribeButton, unsubscribeButton;
77
let topicInput, urgencySelect, notificationInput;
88

9-
function urlB64ToUint8Array(base64String) {
10-
const padding = '='.repeat((4 - base64String.length % 4) % 4);
11-
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
12-
13-
const rawData = window.atob(base64);
14-
const outputArray = new Uint8Array(rawData.length);
15-
16-
for (let i = 0; i < rawData.length; ++i) {
17-
outputArray[i] = rawData.charCodeAt(i);
18-
}
19-
20-
return outputArray;
21-
};
22-
239
function initializeConsole() {
2410
consoleOutput = document.getElementById('output');
2511
document.getElementById('clear').addEventListener('click', clearConsole);
26-
};
12+
}
2713

2814
function clearConsole() {
2915
while (consoleOutput.childNodes.length > 0) {
3016
consoleOutput.removeChild(consoleOutput.lastChild);
3117
}
32-
};
18+
}
3319

3420
function writeToConsole(text) {
3521
var paragraph = document.createElement('p');
3622
paragraph.style.wordWrap = 'break-word';
3723
paragraph.appendChild(document.createTextNode(text));
3824

3925
consoleOutput.appendChild(paragraph);
40-
};
26+
}
4127

4228
function registerPushServiceWorker() {
4329
navigator.serviceWorker.register('/scripts/service-workers/push-service-worker.js', { scope: '/scripts/service-workers/push-service-worker/' })
@@ -50,7 +36,7 @@
5036
}).catch(function (error) {
5137
writeToConsole('Push Service Worker registration has failed: ' + error);
5238
});
53-
};
39+
}
5440

5541
function initializeUIState() {
5642
subscribeButton = document.getElementById('subscribe');
@@ -68,7 +54,7 @@
6854
.then(function (subscription) {
6955
changeUIState(Notification.permission === 'denied', subscription !== null);
7056
});
71-
};
57+
}
7258

7359
function changeUIState(notificationsBlocked, isSubscibed) {
7460
subscribeButton.disabled = notificationsBlocked || isSubscibed;
@@ -77,41 +63,31 @@
7763
if (notificationsBlocked) {
7864
writeToConsole('Permission for Push Notifications has been denied');
7965
}
80-
};
66+
}
8167

8268
function subscribeForPushNotifications() {
8369
if (applicationServerPublicKey) {
8470
subscribeForPushNotificationsInternal();
8571
} else {
86-
fetch('push-notifications-api/public-key')
87-
.then(function (response) {
88-
if (response.ok) {
89-
return response.text();
90-
} else {
91-
writeToConsole('Failed to retrieve Public Key');
92-
}
93-
}).then(function (applicationServerPublicKeyBase64) {
94-
applicationServerPublicKey = urlB64ToUint8Array(applicationServerPublicKeyBase64);
72+
PushNotificationsController.retrievePublicKey()
73+
.then(function (retrievedPublicKey) {
74+
applicationServerPublicKey = retrievedPublicKey;
9575
writeToConsole('Successfully retrieved Public Key');
9676

9777
subscribeForPushNotificationsInternal();
9878
}).catch(function (error) {
9979
writeToConsole('Failed to retrieve Public Key: ' + error);
10080
});
10181
}
102-
};
82+
}
10383

10484
function subscribeForPushNotificationsInternal() {
10585
pushServiceWorkerRegistration.pushManager.subscribe({
10686
userVisibleOnly: true,
10787
applicationServerKey: applicationServerPublicKey
10888
})
10989
.then(function (pushSubscription) {
110-
fetch('push-notifications-api/subscriptions', {
111-
method: 'POST',
112-
headers: { 'Content-Type': 'application/json' },
113-
body: JSON.stringify(pushSubscription)
114-
})
90+
PushNotificationsController.storePushSubscription(pushSubscription)
11591
.then(function (response) {
11692
if (response.ok) {
11793
writeToConsole('Successfully subscribed for Push Notifications');
@@ -130,17 +106,15 @@
130106
writeToConsole('Failed to subscribe for Push Notifications: ' + error);
131107
}
132108
});
133-
};
109+
}
134110

135111
function unsubscribeFromPushNotifications() {
136112
pushServiceWorkerRegistration.pushManager.getSubscription()
137113
.then(function (pushSubscription) {
138114
if (pushSubscription) {
139115
pushSubscription.unsubscribe()
140116
.then(function () {
141-
fetch('push-notifications-api/subscriptions?endpoint=' + encodeURIComponent(pushSubscription.endpoint), {
142-
method: 'DELETE',
143-
})
117+
PushNotificationsController.discardPushSubscription(pushSubscription)
144118
.then(function (response) {
145119
if (response.ok) {
146120
writeToConsole('Successfully unsubscribed from Push Notifications');
@@ -157,7 +131,7 @@
157131
});
158132
}
159133
});
160-
};
134+
}
161135

162136
function sendPushNotification() {
163137
let payload = { topic: topicInput.value, notification: notificationInput.value, urgency: urgencySelect.value };
@@ -176,18 +150,18 @@
176150
}).catch(function (error) {
177151
writeToConsole('Failed to send Push Notification: ' + error);
178152
});
179-
};
153+
}
180154

181155
return {
182156
initialize: function () {
183157
initializeConsole();
184158

185-
if (!'serviceWork' in navigator) {
159+
if (!('serviceWorker' in navigator)) {
186160
writeToConsole('Service Workers are not supported');
187161
return;
188162
}
189163

190-
if (!'PushManager' in window) {
164+
if (!('PushManager' in window)) {
191165
writeToConsole('Push API not supported');
192166
return;
193167
}
Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
const pushNotificationTitle = 'Demo.AspNetCore.PushNotifications';
1+
self.importScripts('/scripts/push-notifications-controller.js');
2+
3+
const pushNotificationTitle = 'Demo.AspNetCore.PushNotifications';
24

35
self.addEventListener('push', function (event) {
46
event.waitUntil(self.registration.showNotification(pushNotificationTitle, {
@@ -7,6 +9,37 @@ self.addEventListener('push', function (event) {
79
}));
810
});
911

12+
self.addEventListener('pushsubscriptionchange', function (event) {
13+
const handlePushSubscriptionChangePromise = Promise.resolve();
14+
15+
if (event.oldSubscription) {
16+
handlePushSubscriptionChangePromise = handlePushSubscriptionChangePromise.then(function () {
17+
return PushNotificationsController.discardPushSubscription(event.oldSubscription);
18+
});
19+
}
20+
21+
if (event.newSubscription) {
22+
handlePushSubscriptionChangePromise = handlePushSubscriptionChangePromise.then(function () {
23+
return PushNotificationsController.storePushSubscription(event.newSubscription);
24+
});
25+
}
26+
27+
if (!event.newSubscription) {
28+
handlePushSubscriptionChangePromise = handlePushSubscriptionChangePromise.then(function () {
29+
return PushNotificationsController.retrievePublicKey().then(function (applicationServerPublicKey) {
30+
return pushServiceWorkerRegistration.pushManager.subscribe({
31+
userVisibleOnly: true,
32+
applicationServerKey: applicationServerPublicKey
33+
}).then(function (pushSubscription) {
34+
return PushNotificationsController.storePushSubscription(pushSubscription);
35+
});
36+
});
37+
});
38+
}
39+
40+
event.waitUntil(handlePushSubscriptionChangePromise);
41+
});
42+
1043
self.addEventListener('notificationclick', function (event) {
1144
event.notification.close();
1245
});

0 commit comments

Comments
 (0)