EddyVerbruggen / nativescript-local-notifications

:mailbox: NativeScript plugin to easily schedule local notifications
MIT License
162 stars 57 forks source link

Navigating to a route after tapping a notification #132

Open joey0xx opened 5 years ago

joey0xx commented 5 years ago

Is there a way I can make the app launch a specific route other than the home after I tap a notification? Or navigate to a route after I tap the notifcation?

im doing this to register the callback for tapping a notification:

ngOnInit() {
        LocalNotifications.addOnMessageReceivedCallback((notification) => {

            this.routerExtension.navigate(["/details", notification.id]);
        })
    }

But i get this error: Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?

I tried wrapping it around ngZone.run() but I still get the same error:

ngOnInit() {
        LocalNotifications.addOnMessageReceivedCallback((notification) => {

             this._zone.run(() => {
                 this.routerExtension.navigate(["/details", notification.id]);
             })
        })
    }
NickIliev commented 5 years ago

@joey0xx see this thread where it is suggested to use the launch event to navigate (when notification is received)

joey0xx commented 5 years ago

@NickIliev Tried using the launch and resume event like this in the home component:

private _notificationId = 0
ngOnInit() { 

        LocalNotifications.addOnMessageReceivedCallback((notification) => {
            this._notificationId = notification.id;

        })
        .then(() => {

            app.on("launch", () => {
                if(this._notificationId > 0){
                    this.navigateToDetails();
                }
            }); 
            app.on("resume", () => {
                if(this._notificationId > 0) {
                    this.navigateToDetails();
                }
            });
        });
    }
    public navigateToDetails() {
        setTimeout(() => {
            this._routerExtensions.navigate(["/details", 0, this._notificationId], {
                transition: {
                    name: "slideTop",
                }
            });
        }, 10000)
    }

But i still get the same error. I dont get the error when wrapping it in NgZone.run() and it looks like it calls .navigate() but it never actually goes into the view.

JDW-Syscom commented 5 years ago

I'm facing the same issue, any update on this?

EddyVerbruggen commented 5 years ago

If this is an issue on Android only, try adding this launchMode to <activity android:launchMode="singleTask" in AndroidManifest.xml.

JDW-Syscom commented 5 years ago

That's not working, if it's any help, I have the firebase plugin as well and it is working with firebase notifications

JDW-Syscom commented 5 years ago

Oh also a thing I noticed is when you did the navigation; while the page you wanted is not seen, pressing the back button on android briefly shows the page you wanted to navigate to and then goes back to the original page.

timdoege commented 5 years ago

I had a similar issue trying to navigate when receiving a local notification, and the reason the navigation was not working was that the callback from the plugin is running outside of Angular's context.

Instead of fiddling with NgZone, I added a simple service exposing a state that indicates if a local notification has been received:

@Injectable()
export class LocalNotificationsService {
    private _state: BehaviorSubject<boolean>;
    constructor() {
        this._state = new BehaviorSubject<boolean>(false);
        LocalNotifications.addOnMessageReceivedCallback(
            (notification: ReceivedNotification) => {
                this.setLocalNotificationPending(true);
            }
        ).catch(
            function() {
              console.log('LocalNotificationsService - unable to add  local notifcations listener');
            }
        );
    }
    public get state(): Observable<boolean> {
        return this._state.asObservable();
    }
    public setLocalNotificationPending(isPending: boolean) {
        this._state.next(isPending);
    }
}

The service is injected in the constructor of app.component in order to set up the callback and can be used in any component from where you want to perform the navigation. For this to work properly, I am setting up the subscription in ngOnInit:

            this.localNotificationService.state.subscribe(y => {
                if (y) {
                    this.doNavigateToReminders = true;
                }
            })

and just set a local variable to indicate that a new state is received. In order for the navigation to be performed properly, you need to initiate it from an Angular lifecycle hook, but since they are not directly connected to the NativeScript lifecycle events of page, I had use a timeout in ngAfterViewInit to ensure the local notifications callback is done and has updated the service before doing the navigation:

    ngAfterViewInit(): void {
        setTimeout(() => {
            if (this.doNavigateToReminders) {
                this.routerExtension.navigate(['/myremindercomponent'], {
                    relativeTo: this.activatedRoute,
                    clearHistory: true
                });
            }
        }, 1000);
    }

This can probably be simplified to be initiated in the subscription part of ngOnInit but depending on the complexity of the view / component where you use this, it is safer to postpone it. Also, if you need to know the ID of the local notification, you can put that into the BehaviorSubject/ state instead of just a boolean.

danielnitu commented 5 years ago

Had the same issue and was able to make it work with NgZone.

setLocalNotificationsCallback() {
    LocalNotifications.addOnMessageReceivedCallback(notification => this.ngZone.run(() => {
        console.log('NOTIFICATION TAPPED', notification)
        this.router.navigate(['main'])
    })).then(() => {
        console.log('NOTIFICATIONS CALLBACK ADDED')
    }).catch(err => {
        console.log('ERROR ADDING NOTIFICATIONS CALLBACK', err)
    })
}

Add the function to app.component.ts and invoke it in ngOnInit.

I'm not 100% sure if this is something that can be corrected. Since the library is made to work with any NS platform, it will run outside Angular's zone, unless it is specifically redesigned for Angular.

Angular 7.2.15 Core 5.4.3 local-notifications 3.2.2