Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open PWA when clicking on push notification handled by service-worker ng7 + android

We've a PWA implemented on angular 7 and NodeJS as backend. Push notification are sent from backend with web-push and handled by the angular service worker service.

The behavior that we hope to have in Android is when the user clicks on the notification, the application opens in the device (i.e. the PWA come up from background and appear visible to the user).

Currently, the code seams to execute in the background but PWA does not come up from background (i.e. the user clicks in the push notification but nothing happens).

The push notification are handled by the angular service called SwPush on front-end, and delivered to app using the following code in the typical AppComponent component of an angular app:

export class AppComponent implements OnInit {
    constructor(private swPush: SwPush) { }

    ngOnInit(): void {
        try {
            if (this.swPush.isEnabled) {
                this.swPush.notificationClicks.subscribe(
                    event => {
                        window.focus();
                        window.open(event.notification.data.url, '_self');
                    },
                    error => {
                        // handle error
                    }
                );
            }
        } catch (err) {
            // handle error
        }
    }
}

I have search all over the SO site and haven't found exactly this question. Comments about other SO questions in order to avoid round trip links to other SO answers:

  • I have read this question, and in my case the console log inside the handler execute without problem
  • this other question seams to proposes a workaround adding code inside the service-worker library, but as far as I understand this is because they are using angular 5 instead of the angular 7 (where the SwPush service include the notificationclick handler). Any way, what I need is to simulate this line:

    event.waitUtil(clients.openWindow(url));

Any idea on how to open the PWA when the user clicks on push notification when using the SwPush service of angular 7?

like image 669
daniel Avatar asked Jan 11 '19 00:01

daniel


People also ask

Does PWA support push notifications?

The possibilities of PWA's are huge, and using DEITY Falcon Platform, you can easily integrate Web Push Notifications directly into your PWA front-end. If you have no plans to convert your website to a web application in the near future, you can also use PushPro as a web push service for your site or eCommerce webshop.

Can PWA access notifications?

Progressive Web Applications (PWA) make native push notifications available to any website using a service worker on just about every platform and browser. The power of web app push notifications is being able to engage customers without a native app.

What is angular service worker?

Adding a service worker to an Angular application is one of the steps for turning an application into a Progressive Web App (also known as a PWA). At its simplest, a service worker is a script that runs in the web browser and manages caching for an application. Service workers function as a network proxy.


4 Answers

Though the provided solutions work, it will be nice to have an approach which does not modify service worker code in node_modules or the generated code.

The approach can be to create another script named custom-service-worker.js

In this file,

importScripts('./ngsw-worker.js');

(function () {
    'use strict';

    self.addEventListener('notificationclick', (event) => {
        console.log("This is custom service worker notificationclick method.");
        console.log('Notification details: ', event.notification);
        // Write the code to open
        if (clients.openWindow && event.notification.data.url) {
            event.waitUntil(clients.openWindow(event.notification.data.url));
        }
    });}
());

Register custom-service-worker.js as the service worker in place of ngsw-worker.js in the imports section where ServiceWorkerModule.register would be written.

Also don't forget to add this script as asset in angular.json so that it gets copied in the dist folder.

I believe this approach saves us the hassle of doing anything extra to edit the original service worker file.

like image 56
Jay Avatar answered Oct 09 '22 14:10

Jay


Unfortunately you won't be able to open your PWA from angular code. The SwPush interface will work nicely if the app is currently open.

If your application is closed, the only thing running will be your service worker (provided it was registered succesfully). So the solution to your problem is editing angular's service worker file.

In angular 7 (specifically referring to "@angular/service-worker" v~7.2.0), after you build your app with ng build --prod, examine your /dist folder and look for the file ngsw-worker.js. Open it in an editor.

On line 1885, you will find:

this.scope.addEventListener('notificationclick', (event) => this.onClick(event));

Change it to:

this.scope.addEventListener('notificationclick', (event) => {
    event.notification.close();
    if (clients.openWindow && event.notification.data.url) {
        event.waitUntil(clients.openWindow(event.notification.data.url));
    }
});

This implies that you passed in the notification payload a data object with the desired URL. e.g:

{ 
    title: "Hello", 
    body: "Here, open this URL",
    data: { 
        url : "/somewhere/over/the/rainbow/42"
    } 
}

Things to have in mind:

  • If you have any automated build pipelines (CD), you'll have to change your ngsw-worker.js manually (but you could manage to deploy your service worker file after ng build --prod process completes) ;
  • Everytime you build to prod, ngsw-worker.js will be overwritten. @Jay's answer below offer a better approach to avoid this problem.
  • I know you are developing on android, but if you're having trouble seeing changes, you could use Chrome Dev tools to [A] force update the service worker or [B] to open the current ngsw-worker.js file and verify if it's the desired version. The solution works for installed apps on your desktop as well.

enter image description here

Related links:

How can I initiate a PWA (progressive webapp) open from a click on a push notification?

https://github.com/angular/angular/issues/20956

like image 34
tomblue Avatar answered Oct 09 '22 14:10

tomblue


Add this on your Angular project inside the node_modules/@angular/service-worker/ngsw-worker.js

this.scope.addEventListener('notificationclick', (event) => {
            console.log('[Service Worker] Notification click Received. event:%s', event);
            event.notification.close();
            if (clients.openWindow && event.notification.data.url) {
                event.waitUntil(clients.openWindow(event.notification.data.url));
            }
        });

You can enter the above code where you can find this line inside the file

this.scope.addEventListener('notificationclick', (event) => ..

And you have to build the dist again for this to work. And in backend you would need to use this format:

{"notification":{"body":"This is a message.","title":"PUSH MESSAGE","vibrate":[300,100,400,100,400,100,400],"icon":"https://upload.wikimedia.org/wikipedia/en/thumb/3/34/AlthepalHappyface.svg/256px-AlthepalHappyface.svg.png","tag":"push demo","requireInteraction":true,"renotify":true,"data":{"url":"https://maps.google.com"}}}

Inside the url you can enter your url and on clicking notification your push notification will open the given link and focus it in the browser. YOu dont need to change anything inside the dist.

like image 1
cyperpunk Avatar answered Oct 09 '22 13:10

cyperpunk


The best way is to extend the Angular Cli Generated Service Worker. Changing anything inside the node_modules is strongly not recommended.

Step 1: Simply create a new my-svc-wkr.js in your root folder and implement as many event listeners as you want for example:

importScripts('./ngsw-worker.js'); // This will import the default Angular Service Worker Functionality to your custom file.

// Add additional Event Listners like Below:
self.addEventListener('notificationclick', (event) => {
  console.log('notification clicked!')
});

Step 2: Now replace the service worker file in your app.module.ts as follows:

ServiceWorkerModule.register('my-svc-wkr.js', { enabled: environment.production })

Step 3: Add following in your angular.json to copy this file during build process in your dist directory:

"assets": {
  ...,
  "src/my-svc-wkr.js"
}

You may read this article for a more detailed explanation on extending service worker functionality: https://medium.com/@smarth55/extending-the-angular-cli-service-worker-44bfc205894c

like image 1
Arslan Ali Avatar answered Oct 09 '22 13:10

Arslan Ali