Reputation: 4386
I'm creating a PWA using angular 7, but I'm struggling with the push notifications.
I was following the tutorials as this and this using SWPush and Vapid keypairs. I was able to subscribe and unsubscribe and my server part works as well, but unfortunately the tutorials do not cover showing the actual notification in the app.
As I understood it, the notifications should pop up automatically without calling it in the code, right?. You just subscribe and the ngsw does the rest. Unfortunately they don't show up in my case. I can show them only by manually calling them in the code like this:
this.swPush.messages.subscribe(
(notification: any) => {
console.log("received push message", notification);
let options = {
body: notification.body,
icon: "assets/icon/favicon.png",
actions: <any>notification.actions,
data: notification.data,
vibrate: [100, 50, 10, 20, 20]
};
this.showNotification(notification.title, options)
},
err => {
console.error(err);
}
);
[...]
showNotification(title: string, options: NotificationOptions) {
navigator.serviceWorker.getRegistration().then(reg => {
reg.showNotification(title, options).then(res => {
console.log("showed notification", res)
}, err => {
console.error(err)
});
});
}
But this seems to work only when the app/page is in foreground. Otherwise I get a notification like "The site has been updated in the background". Obviously I am doing something wrong here.But what?
What do I have to do to show notifications when the app is in the background?
Is there a way to handle click events on the notifications?
The ng documentation is really sparse here.
Upvotes: 8
Views: 7416
Reputation: 4386
After lots of struggle I found something and will share it for others:
Digging into the ngsw-worker.js that is created by running build --prod there is this function:
onPush(msg) {
// Push notifications without data have no effect.
if (!msg.data) {
return;
}
// Handle the push and keep the SW alive until it's handled.
msg.waitUntil(this.handlePush(msg.data.json()));
}
...
handlePush(data) {
return __awaiter$5(this, void 0, void 0, function* () {
yield this.broadcast({
type: 'PUSH',
data,
});
if (!data.notification || !data.notification.title) {
return;
}
const desc = data.notification;
let options = {};
NOTIFICATION_OPTION_NAMES.filter(name => desc.hasOwnProperty(name))
.forEach(name => options[name] = desc[name]);
yield this.scope.registration.showNotification(desc['title'], options);
});
}
As it looks like angular subscribes and shows the notification for you, it is not necessary to subscribe and show it in your own code. I had an issue with my sending library (https://github.com/laravel-notification-channels/webpush) that was sending the payload like this:
payload = {"title":"test","actions":[{"title":"View App","action":"view_app"}],"body":"test","icon":"\/icon.png","data":{"id":"21a3804e-6d71-4a56-b513-535709c37c0f"}}
but angular expects obviously something like:
payload = {
"notification":{"title":"test","actions":[{"title":"View App","action":"view_app"}],"body":"test","icon":"\/icon.png","data":{"id":"21a3804e-6d71-4a56-b513-535709c37c0f"}}
}
which caused this line in ngsw-worker.js to fail:
if (!data.notification || !data.notification.title) {
return;
}
Therefor, no notification was shown, but the browser reported an update in the background. Hope this helps someone.
Upvotes: 10
Reputation: 41
Is there a way to handle click events on the notifications?
Try this:
this.swPush.notificationClicks.subscribe(data => {
// handle click
})
Upvotes: 4