How to Get APNS payload from a remote push notification? - ios

I am working on adding Remote push notification support in my OSX application. I can successfully receive the push notification in my PC via apns and when I click the notification banner this is the behavior I am seeing.
If my app is not running , it will launch the application. But never hits on "ReceivedRemoteNotification()". Is this expected behavior ? Is there any way to receive the apns payload in this case ?
If my app is running I get the payload via "ReceivedRemoteNotification" and things are working fine.
So we cannot get apns payload in our app if it is not running?
Any help really appreciated.
thanks,
Jithesh

Figured it out. The payload is available through "NSNotification" parameter of DidFinishLaunching.
public override void DidFinishLaunching(NSNotification notification)
{
var uInfo = notification.UserInfo;
if(uInfo["NSApplicationLaunchUserNotificationKey"] != null)
{
var payLoad = uInfo["NSApplicationLaunchUserNotificationKey"] as NSUserNotification;
if(payLoad.ActivationType == NSUserNotificationActivationType.ActionButtonClicked)
{
NSAlert alert = new NSAlert();
alert.MessageText = "Button Clicked";
alert.RunModal();
}
var userInfo = payLoad.UserInfo;
//not.ActivationType ==
if (userInfo != null && userInfo.ContainsKey(new NSString("aps")))
{
//Get the aps dictionary
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
if (aps.ContainsKey(new NSString("content")))
{
var deepLink = (aps[new NSString("content")] as NSString).ToString();
NSAlert alert = new NSAlert();
alert.MessageText = deepLink;
alert.RunModal();
//DisplaySubView(deepLink);
//Console.WriteLine($"Deeplink : {deepLink}");
}
}
}

Related

Xamarin.IOS does not receive firebase notifications but registers fcmToken

Hello I need some suggestions what may be the reason why my notifications are sent but I never receive them on my phone, also its debugged on physical device -> iPhone X (14.3).
I have followed this article https://github.com/xamarin/GoogleApisForiOSComponents/blob/main/docs/Firebase/CloudMessaging/GettingStarted.md for implementing firebase notifications on IOS.
I added APNs Authentication Key to firebase that i downloaded from my developer acc.
I added in my info.plist
property FirebaseMessagingAutoInitEnabled -> No
selected Enable Background Modes and selected Remote Notifications
In GoogleService-Info.plist Build Action -> Bundle Resource
I have double checked my bundle_id, my project and in GoogleService-Info are the same.
In Entitlements.plist selected Remote Notifications
Here is my AppDelegate.cs
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
private App app;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init();
DependencyService.Register<ILocalStorageManager, LocalStorageManager>();
DependencyService.Register<ILauncherService, LauncherService>();
LoadApplication(new App());
Firebase.Core.App.Configure();
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
Console.WriteLine(granted);
});
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
Messaging.SharedInstance.Delegate = this;
var token = Messaging.SharedInstance.FcmToken ?? "";
Console.WriteLine($"FCM token: {token}");
return base.FinishedLaunching(app, options);
}
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
Console.WriteLine($"Firebase registration token: {fcmToken}");
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
var userInfo = notification.Request.Content.UserInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
// Change this to your preferred presentation option
completionHandler(UNNotificationPresentationOptions.None);
}
// Handle notification messages after display notification is tapped by the user.
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
var userInfo = response.Notification.Request.Content.UserInfo;
// Print full message.
Console.WriteLine(userInfo);
completionHandler();
}
}}
In Console it generates my FCM token and when I try to send notification from Firebase Console nothing is printed in the console but it says its completed. Then I tried to sent it from postman and I received the next message.
{
"multicast_id": 5300302940762876386,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1627386458132596%db948e52db948e52"
}
]}
My nugget packages IOS.CloudMessaging, IOS.Core, iOS.Installations and iOS.IstanceID are up todate.
I found my problem.
I overrided FailedToRegisterForRemoteNotifications and saw that it throwed
"no valid “aps-environment” entitlement string found for application"
and I checked that my bundle identifier in info.plist was ok, but in my xCode project was wrong and that solved my problem.

Quickblox iOS notification when a new dialog is added

Is there a iOS notification that we get in ServiceManager (QMServicesManager), chatService to notify the app that a new Dialog is added for the user. Basically a brand new chat request
You could use QuickBlox's System notifications to send the message to the recipient after creating a dialog
let message: QBChatMessage = QBChatMessage()
let params = NSMutableDictionary()
params["event_type"] = "NewDialogCreated"
params["dialogId"] = <dialogId or the information you need to pass>
message.customParameters = params
message.recipientID = UInt(recipientId)!
QBChat.instance.sendSystemMessage(message) { (Error) in
}
and recipient could receive this message in QBChatdelegate
#pragma mark QBChatDelegate
func chatDidReceiveSystemMessage(message: QBChatMessage!) {
}

Swift Send additional data through Notification

How can I pass additional data in my notifications im currently using Onesignal to send notification. im not sure if im using the key additionalData to send the additional data. I receive the notification but I do not receive the additional Data
//my custom completion handler to retrieve user token
self.getUserInfoCustom(userIdSearching: sendNotifToUser, completion: { (userInfo) in
// send notif
if let notif = userInfo?.deviceToken {
let value:NSMutableDictionary = [:]
value["include_player_ids"] = [notif]
value["contents"] = ["en": "Test Message"]
let additionalData = ["name":"Pierre"]
value["additionalData"] = additionalData
OneSignal.postNotification((value as NSDictionary) as! [AnyHashable:Any])
}
})
Instead of using additionalData, just use data

Send tag to OneSignal after log in

I want to send tag to a specific user after he/she logged in so he/she can receive notifications. Only logged in users will receive notifications.
When he/she logs out, I will delete his/her tag.
How can I do this?
My code in AppDelegate:
let oneSignal: OneSignal = OneSignal(launchOptions: launchOptions, appId: "<my-app-id>") {
(message, additionalData, isActive) in
if (additionalData != nil) {
NSLog("APP LOG ADDITIONALDATA: %#", additionalData);
let displayMessage: NSString = NSString(format:"NotificationMessage:%#", message);
var messageTitle: NSString = "";
if (additionalData["discount"] != nil) {
messageTitle = additionalData["discount"] as String
}
else if (additionalData["bonusCredits"] != nil) {
messageTitle = additionalData["bonusCredits"] as String;
}
else if (additionalData["actionSelected"] != nil) {
messageTitle = NSString(format:"Pressed ButtonId:%#", additionalData["actionSelected"] as String);
}
var alertView: UIAlertView = UIAlertView(title: messageTitle,
message:displayMessage,
delegate:self,
cancelButtonTitle:"Close");
alertView.show();
}
else if (isActive) {
var alertView: UIAlertView = UIAlertView(title:"OneSignal Message",
message:message,
delegate:self,
cancelButtonTitle:"Close");
alertView.show();
}
}
My code in my LogInViewController:
let oneSignal = OneSignal()
oneSignal.sendTag("username", value: self.usernameTextField.text)
The code in my appDelegate is working fine, my users already receive notifications. But they can receive notifications even if they're not logged in.
You need to use the same oneSignal instance from AppDelegate in your LogInViewController. You can make oneSignal static at the class level so it can be shared between both classes.
To delete a tag you can call oneSignal.deleteTag("username")
Update:
As of the iOS 2.0 SDK all methods on the OneSignal class are now static.
Objective-C:
// Send tag: After login
[OneSignal sendTag:#"key" value:#"value"];
// Delete tag: After logout
[OneSignal deleteTag:#"key"];
Swift:
// Send tag: After login
OneSignal.sendTag("key", value: "value") // for sending that is inserting tag in OneSignal
// Delete tag: After logout
OneSignal.deleteTag("key") // delete that specific tag from OneSignal db

Using amazon AWS SNS service IOS

I am developing an app which uses amazon aws service and it is a messenger.
I would like to use IOS Push Notification service and the amazon SNS to achieve the communication between 2 users. I am able to send message from the SNS console by publishing a message to the destination called endpoint.
However, i am not able to send message from one mobile to another mobile by amazon SDK of IOS. Can i do it in that way by the API of Amazon?
I want to send the NSDictionary called messageDict to the destination endPoint. Can i achieve this without the use of server??
NSDictionary *messageDict = [[NSDictionary alloc]init];
messageDict = #{ #"Name" : #"HelloWrold" ,#"Id" :#"GoodBye",};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:messageDict options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"Jsonstring %#",jsonString);
AWSSNS *publishCall = [AWSSNS new];
AWSSNSPublishInput *message = [AWSSNSPublishInput new];
message.subject = #"My First Message";
//This is the ending point
message.topicArn = #"arn:aws:sns:us-east-1:012345678912:endpoint/APNS_SANDBOX/appTesting/201sjad-XXXX-XXXX-XXXX-c34sdfdsf1d9c";
message.messageAttributes = messageDict;
message.messageStructure = jsonString;
[[publishCall publish:message]continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task){
if (task.error != nil) {
NSLog(#"Error %#",task.error);
}
else{
NSLog(#"Successful");
}
return nil;
}];
The hardest thing about sending an APN with SNS is getting the data structure correct. Here is how you you can publish to a topic using swift. Each platform needs to be an encoded string, if you mess this up SNS will only deliver your default message.
func publishPush() {
let sns = AWSSNS.defaultSNS()
let request = AWSSNSPublishInput()
request.messageStructure = "json"
var aps: NSMutableDictionary = NSMutableDictionary()
var dict = ["default": "The default message", "APNS_SANDBOX": "{\"aps\":{\"alert\": \"YOUR_MESSAGE\",\"sound\":\"default\", \"badge\":\"1\"} }"]
let jsonData = NSJSONSerialization.dataWithJSONObject(dict, options: nil, error: nil)
request.message = NSString(data: jsonData!, encoding: NSUTF8StringEncoding) as! String
request.targetArn = "blahblahblah:MyTopic"
sns.publish(request).continueWithBlock { (task) -> AnyObject! in
println("error \(task.error), result:; \(task.result)")
return nil
}
}
You can either send a push notification to a specific device (endpoint) or to a topic (list of multiple subscribers)
The API call is slightly different for both. Either you use message.topicArn or message.targetArn as describe in the API documentation here
http://docs.aws.amazon.com/sns/latest/api/API_Publish.html
(Objective-C class documentation is here : http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSSNSPublishInput.html)
Your ARN is an Endpoint ARN and your code assigns it to message.topicArn
I would change it to
message.targetArn = #"arn:aws:sns:us-east-1:123456789012:endpoint/APNS_SANDBOX/appTesting/201sjad-XXXX-XXXXXX-XXXX-c34sdfdsf1d9c";
(ARN edited to obfuscate your Account ID)
Also, please read and apply best practice from http://mobile.awsblog.com/post/Tx223MJB0XKV9RU/Mobile-token-management-with-Amazon-SNS to acquire and manage your device token.
Here is a code sample in Javascript, that you easily adapt to Objective-C.
var DEFAULT_SNS_REGION = 'eu-west-1';
var SNS_ENDPOINT_ARN = 'arn:aws:sns:eu-west-1:0123456789012:endpoint/APNS_SANDBOX/AmazonSNSPushDemo/95084b8f-XXXX-XXXX-XXXX-b3429d0fa528';
var SNS_TOPIC_ARN = 'arn:aws:sns:eu-west-1:012345678912:PushNotifications';
function sendNotification(msg, topicARN, endPointARN) {
var sns = new aws.SNS({
apiVersion: '2010-03-31',
region: DEFAULT_SNS_REGION
});
var params = {}
if (topicARN != '') {
params = {
Message: msg,
//MessageStructure: 'json',
TopicArn: topicARN
};
} else {
params = {
Message: msg,
//MessageStructure: 'json',
TargetArn: endPointARN
};
}
console.log(params);
var deferred = Q.defer();
sns.publish(params, function(err,data) {
if (err) {
console.log(err, err.stack); // an error occurred
deferred.reject(err);
} else {
console.log(data); // successful response
deferred.resolve(data);
}
});
return deferred.promise; }
The AWSSNS instance is not correctly instantiated.
AWSSNS *publishCall = [AWSSNS new];
needs to be changed to
AWSSNS *publishCall = [AWSSNS defaultSNS];
In general, however, I do not recommend sending push notifications from the client devices because anyone can grab the temporary credentials from the mobile device and spam your app users. Amazon SNS currently does not support fine-grain access control nor throttling the excessive send requests.
The better solution from the security point of view is to have a push notification server. You can take a look at some of the services that may help:
AWS Lambda
AWS Elastic Beanstalk

Resources