roblav96 / nativescript-onesignal

A Nativescript plugin that wraps the iOS and Android OneSignal Push Notifications SDK.
https://documentation.onesignal.com/docs/getting-started
Other
24 stars 42 forks source link

handleNotificationOpen callback #23

Open leopoldv opened 6 years ago

leopoldv commented 6 years ago

Is there an example on how to use handleNotificationOpen on Android and iOS?

alexandruantonica commented 6 years ago

I have the same question.

leopoldv commented 6 years ago

@alexandruantonica I found a solution on my own eventually so here it goes:

For Android: var nativescript_onesignal_1 = require('nativescript-onesignal'); nativescript_onesignal_1.TnsOneSignal.init(applicationModule.android.context,"" ,"",new nativescript_onesignal_1.TnsOneSignal.NotificationOpenedHandler({ notificationOpened: function (result) { var Obj = JSON.parse(result.notification.payload.rawPayload);

                if(Obj.actionSelected === "your action")
                {                            
                    "do something"
                }  
            },
        }));
alexandruantonica commented 6 years ago

@leopoldv I work in Nativescript with Angular. My code should looks like that ? I used received instead of opened.

if (application.android) {
    application.on(application.launchEvent, function(args: application.ApplicationEventData) {
        try {
            TnsOneSignal.startInit(application.android.context).init();
            TnsOneSignal.NotificationReceivedHandler({
                                  notificationReceived : result => {
                                       console.log('=====> Notification received !!! ');
                                   }
                         })
        } catch (error) {
            console.error('error', error)
        }
    })
}

I also tried your way too.

TnsOneSignal.NotificationOpenedHandler({
       notificationOpened : result => {
                    console.log('=====> Notification opened !!! ');
                }
       })

It doesn't work.

GustavoEdinger commented 6 years ago

@alexandruantonica You need to set the handler in the constructor, something like this:

    TnsOneSignal.init(application.android.context,"" ,"",new
        TnsOneSignal.NotificationOpenedHandler({
            notificationOpened: function (result) {
                console.log(result.notification.payload.rawPayload);
                var obj = JSON.parse(result.notification.payload.rawPayload);
            },
        })
    );
alexandruantonica commented 6 years ago

Hi @Gustavo47 It does work when I use this :

TnsOneSignal.startInit(application.android.context)
                .setNotificationReceivedHandler(new TnsOneSignal.NotificationReceivedHandler({
                    notificationReceived: notification => {
                        console.log(notification.payload);
                    }
                }))
                .init();

But I tried to do the same thing (to catch the notification) on iOS but I failed.

The only function that works is initWithLaunchOptionsAppId( launchOptions, appId). In documentation says we should use initWithLaunchOptions( launchOptions, appId, HandleNotificationReceivedBlock, ...) but when I try this, nativescript told me that initWithLaunchOptions is not a function.

Do you have any idea ?

endymion00 commented 6 years ago

hi @alexandruantonica, Idid you make it work for iOS? I don't understand why initWithLaunchOptions it is not available although in theory the lastest framework must be used (according the podfile)

alexandruantonica commented 6 years ago

@endymion00 Yes, I did. I have created a service responsible for push notifications and there is where I initiated the OneSignal plugin. Here you can find a piece of @roblav96's service.

Basically initWithLaunchOptions was split into multiple methods where you can choose which one you need. If you check the typing, you'll understand. initWithLaunchOptionsAppId initWithLaunchOptionsAppIdHandleNotificationAction initWithLaunchOptionsAppIdHandleNotificationActionSettings initWithLaunchOptionsAppIdHandleNotificationReceivedHandleNotificationActionSettings

In my case I used initWithLaunchOptionsAppIdHandleNotificationReceivedHandleNotificationActionSettings because this is what I need to handle notifications. and my init function looks like that.

public static init(options): void {
        if( application.ios){
            let opts = NSMutableDictionary.new();
            opts.setValueForKey(false, 'kOSSettingsKeyAutoPrompt');
            opts.setValueForKey(true, 'kOSSettingsKeyInAppLaunchURL');
            opts.setValueForKey( 2, 'kOSSettingsKeyInFocusDisplayOption');
            TnsOneSignal.initWithLaunchOptionsAppIdHandleNotificationReceivedHandleNotificationActionSettings(
                options,
                NotificationsService.appId,
                function receivedCallback(notification) {
                    NotificationsService.onReceived({
                        title: notification.payload.title,
                        body: notification.payload.body,
                        data: NotificationsService.parseJson(notification.payload.additionalData),
                    })
                },
                function actionCallback(result) {

                },
                opts
            );

            TnsOneSignal.IdsAvailable(NotificationsService.idsAvailable);
        }

        if( application.android){
            TnsOneSignal.startInit(options)
                .autoPromptLocation(false)
                .unsubscribeWhenNotificationsAreDisabled(true)
                .inFocusDisplaying(TnsOneSignal.OSInFocusDisplayOption.Notification)
                .setNotificationReceivedHandler(new TnsOneSignal.NotificationReceivedHandler({
                    notificationReceived: function(notification) {
                        NotificationsService.onReceived({
                            title: notification.payload.title,
                            body: notification.payload.body,
                            data: NotificationsService.parseJson(notification.payload.additionalData),
                        })
                    },
                }))
                .init();

            TnsOneSignal.idsAvailable(new TnsOneSignal.IdsAvailableHandler({
                idsAvailable: NotificationsService.idsAvailable,
            }));
        }
    }

And this is my main.ts and main.aot.ts file

if (application.android) {
    application.on(application.launchEvent, function(args: application.ApplicationEventData) {

        try {
            NotificationsService.init(application.android.context);

        } catch (error) {
            console.error('error', error)
        }

    })
}

if (application.ios) {
    class MyDelegate extends UIResponder implements UIApplicationDelegate {

        public static ObjCProtocols = [UIApplicationDelegate];

       applicationDidFinishLaunchingWithOptions(app: UIApplication, launchOptions: any): boolean {

           try {
               NotificationsService.init(launchOptions);
            } catch (error) {
                console.error('error', error)
            }
            return true
        }

   }
    application.ios.delegate = MyDelegate
}

I hope I helped you with this information. Cheers 👍

endymion00 commented 6 years ago

@alexandruantonica thank you very much for you help! I will try it :) In my case I need to handle when the user "opens" the push notification in order to navigate to a specific page. If I'm not wrong the method you are using (in iOS) it is triggered when the push notification arrives. By the way, just for curiosity, NotificationsService.onReceived which I suppose it is a custom emthod method, does it emit an event or similar in order to perform some action? I'm interested in how to achieve it.

Best regards

alexandruantonica commented 6 years ago

@endymion00 There is an empty function with actionCallBack() because I don't need it. There is the place where you can add your code to handle actions of users (click on notification). Yes, NotificationService.onReceived is a custom method from my service that handle notifications onReceived event. You can create a method like this one where you can handle the onAction event.

My onReceived method looks like that

private static onReceived(notification: NotificationView): void {
        this._notifications.next(notification);
    }

Where this._notifications is a BehaviorSubject. NotificationService is also an injectable service, when you inject this service in your component (in root or something like that), you can use this BehaviorSubject that is triggered every time when the user receives a notification (or takes an action, in your case).

Cheers 👍

endymion00 commented 6 years ago

@alexandruantonica great I will apply the same strategy :) As I see I'm having trouble with parsing additionalData from iOS. I have a function called parsePushMessageIos that parses the message. It does not fail and in theory is getting all keys inside additionalData but for some reason I can process the result of the function. JSON.stringify is not showing the content and JSON.parse fails. As I see you have a parse method inside your Notification service, I'm wondering how are you parsing additionalData inside the payload?


function getObjectFromNsDictionary(iosNsDictionary) {
    let result = {};
    for (let key of iosNsDictionary) {
        console.log('getObjectFromNsDictionary, key:', key);
        console.log('getObjectFromNsDictionary, value:', iosNsDictionary.objectForKey(key));
        result[key] = iosNsDictionary.objectForKey(key);
    }
    return result;
}
function parsePushMessageIos(message) {
    console.log("----Notification data ios ----------------");    
    const notification = message;
    const payload = notification.payload;
    const title = payload.title;
    const body = payload.body;
    const data = getObjectFromNsDictionary(payload.additionalData);
    return { title: title, body: body, data: data };
}

Best regards!

alexandruantonica commented 6 years ago

@endymion00 This is my parseJson method and I use it for data field.

notificationReceived: function(notification) {
                        NotificationsService.onReceived({
                            title: notification.payload.title,
                            body: notification.payload.body,
                            data: NotificationsService.parseJson(notification.payload.additionalData),
                        })
                    },
private static parseJson(json): any {
        if (application.ios) {
            if (!json) {
                return json
            }
            let data = NSJSONSerialization.dataWithJSONObjectOptionsError(json, NSJSONWritingOptions.PrettyPrinted);
            let results = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding);
            return JSON.parse(<any>results);
        }

        if (application.android) {
            return (json) ? JSON.parse("" + json) : json;
        }
    }
endymion00 commented 6 years ago

@alexandruantonica for some reason that code failed (maybe because I am using NS 3.4.2 version), but I noticed that the my previous code was working. An unhandled error related to navigation confused me about the real reason. As I saw there is a problem with navigating to another page when using the notification opened handler but probably it is due to lack of knowledge about how to handle this properly (and how to deal with app life cycles). For example I can't make Android to trigger the "on receive notification" when the app is in "not running" state but it works when the app is suspended or in foreground. Thanks you very much for your time :)

markosole commented 4 years ago

Hi guys, I am receiving notifications and taking certain actions when notification is opened. If app is running in background, handling received data works (payload is received). But if app is killed and notification opened, it's just does not receive any payload (does not process it).

My code is below:

if (application.android) {  
  application.on(application.launchEvent, function(args) {
    try {  
            TnsOneSignal.startInit(application.android.context).init();
            TnsOneSignal.init(application.android.context,"" ,"",new
                TnsOneSignal.NotificationOpenedHandler({
                    notificationOpened: function (result) {  
                        var obj = JSON.parse(result.notification.payload.rawPayload); 
                        var obj2 = JSON.parse(obj.custom) 

                        switch(obj2.a.vrsta) {
                                case "kategorija":       
                                appSettings.setString("vrsta", obj2.a.vrsta); 
                                appSettings.setString("vrsta-id", obj2.a.id); 
                                  break;  

                                  case "novost":              
                                  appSettings.setString("vrsta", obj2.a.vrsta); 
                                  appSettings.setString("vrsta-id", obj2.a.id); 
                                  break; 

                                default:
                                  // code block
                        } 
                    },
                })
            ); 
            TnsOneSignal.setSubscription(true);   
            var status=TnsOneSignal.getPermissionSubscriptionState();
            console.log("Player ID is: " + status.getSubscriptionStatus().getUserId()); 

    } catch (error) {
        console.log('error', error);
    }
})

}

Looks like this never fires when app is killed and opened from received notification. Do I need different method for app which isn't running in background? Thx