You get the notification info in the code if you tap the notification from notification center, but what if user won't tap this, and will just tap the app icon on the home screen?
For example because the notification payload contained also badge property. Then user can tap the app icon, because there is badge number shining, but how do you manage the waiting notifications in the code in this case?
If there is no method for this, then the badge property in notification payload is bit useless, isn't it. Because if user taps the icon with badge number he expects that something will happen, but app is unable to do anything with pending notifications, thus to do anything. Or?
It seems that getDeliveredNotifications method allows this.
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(#"msg applicationWillEnterForeground");
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// https://stackoverflow.com/a/52840551
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
NSLog(#"msg getDeliveredNotificationsWithCompletionHandler count %lu", [notifications count]);
for (UNNotification* notification in notifications) {
// do something with object
NSLog(#"msg noti %#", notification.request);
}
}];
#endif
}
Related
I'm using Cordova and the plugin phonegap-plugin-push,
when my app is in foreground I don't see the notification alert.
What I have to do?
(I know the way to do it on Android platform (setting "forceShow": true in the method init of PushNotification) but this works only for Android)
Thank you in advance for your replies.
If u don't want to touch ios native things, then you can display your own custmize html/css Banner (like iOS push Baner) in following method :
push.on('notification', function(data) {
If(platform == "iOS" && data.additionalData.foreground){
// Show your Baner here
// U can also define call back on clicking of that banner
//Like navigation to respective page or close that banner
});
Denise,
Notification doesn't work in the foreground. It only works in the background. Do handle it in the foreground you need to implement the logic in the delegate method.
Below is the Objective C code snippet to show the notification in the foreground.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
application.applicationIconBadgeNumber = 0;
//self.textView.text = [userInfo description];
// We can determine whether an application is launched as a result of the user tapping the action
// button or whether the notification was delivered to the already-running application by examining
// the application state.
if (application.applicationState == UIApplicationStateActive)
{
// Nothing to do if applicationState is Inactive, the iOS already displayed an alert view.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Did receive a Remote Notification" message:[NSString stringWithFormat:#"Your App name received this notification while it was running:\n%#",[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]]delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
It will help you for your problem.
In iOS if your app is in foreground, push notification alert will not show. To achieve it, you should write code for alert in push notification receive delegate if your application is in foreground. To know application state in iOS this is the code.
+(BOOL) runningInForeground
{
UIApplicationState state = [UIApplication sharedApplication].applicationState;
return state == UIApplicationStateActive;
}
In a nut shell, I have three views: Main View, List View (to display the buddies list) and Chat View(where you chat).
The push notification is correctly setup in this app, so I have no problems in receiving the push notification payload, my question lies on why in a specific scenario the received message seemed lost and doesn't appear in Chat View
I have a strange problem, so please carry on read the whole description:
So here I put some code to show how I handle the push notifications:
In AppDelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Extract the Sinch-specific payload from the Apple Remote Push Notification
NSString* payload = [userInfo objectForKey:#"SIN"];
[self initSinchClientWithUserId:userid];
// Get previously initiated Sinch client
id<SINNotificationResult> result = [_client relayRemotePushNotificationPayload:payload];
if ([result isMessage]) {
// Present alert notifying
NSString *messageId = [[result messageResult] messageId];
NSLog(#"Received messageid: %#", messageId);
if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground ||
[UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
self.messageSenderId = [[result messageResult] senderId];
[[NSNotificationCenter defaultCenter] postNotificationName:#"ReceivedRemoteNotification" object:self userInfo:nil];
NSLog(#"handle remote notification in modal");
} else {
self.messageSenderId = [[result messageResult] senderId];
// this will launch a modal of private chat, so better to invoke this when running in background
[[NSNotificationCenter defaultCenter] postNotificationName:#"SetUnreadIcon" object:self userInfo:nil];
NSLog(#"handle remote notification by marking icons");
}
} else if (![result isValid]) {
// Handle error
}
NSLog(#"Received Payload: %#", payload);
}
In Main View, handles ReceivedRemoteNotification and SetUnreadIcon
-(void) viewDidLoad {
[super viewDidLoad];
....
// setup a local notification handler
NSNotificationCenter *notifCentre = [NSNotificationCenter defaultCenter];
[notifCentre addObserver:self selector:#selector(invokeRemoteNotifications:) name:#"ReceivedRemoteNotification" object:nil];
[notifCentre addObserver:self selector:#selector(setUnreadIcon:) name:#"SetUnreadIcon" object:nil];
....
}
- (void)invokeRemoteNotifications: (NSNotification *) notification {
shouldDismiss = NO;
[self invokeNotifications];
}
- (void)invokeNotifications {
[self performSegueWithIdentifier:#"modalToChat" sender:self];
}
- (void)setUnreadIcon: (NSNotification *) notification {
AudioServicesPlaySystemSound (1300);
shouldDismiss = YES;
[self.rightbutton setCustomView:notifyButton];
}
When user tap rightbutton in MainView, will call up the ListView.
In ChatView, it implements SINMessageClientDelegate delegate methods (See Documentation), namely
– messageClient:didReceiveIncomingMessage:
– messageSent:recipientId:
– messageDelivered:
– messageFailed:info:
– message:shouldSendPushNotifications:
The Working Scenario
Assume user Alice send message to Bob. Bob received this message via push notification. So Bob open and tap the notifications, the app will show up and automatically showing a modal view of ChatView.
In this case, the message from the push notifications can be displayed in Chat View
The Not Working Scenario
Assume user Alice send msg to Bob again, this time Bob received the notification while the app is in foreground. So this method will be executed:
- (void)setUnreadIcon: (NSNotification *) notification {
AudioServicesPlaySystemSound (1300);
shouldDismiss = YES;
[self.rightbutton setCustomView:notifyButton];
}
Then Bob will tap rightbutton to call up ListView, find Alice and open the conversation. Bob will find that the message just received from Alice is not displayed in ChatView
Questions
In Sinch SDK, there seemed no approach to manually retrieve the messages even the messageId is retrieved while receiving the push notification. Am I correct?
In the "Not Working" case, why the message is lost? If the sinch client is responsible for relaying the messages, what reason to make it discard the messages?
Still in the "Not Working" case, how I can persist the messages, and then later display it? Must I implement the SINMessageClientDelegate elsewhere?
Thanks,
Regarding your first question, there is no way to query for a particular message in that way you are describing.
The problem for your "Not Working"-case is likely that by the time the Sinch SDK fetches the instant message and is about to notify the message client delegate, your Chat View has not yet been instantiated / assigned to be the delegate, and because of that the message is "missed" by the delegate.
I would recommend you to have a non-ViewController component implement the SINMessageClientDelegate, and make that component have a life-cycle that is independent of your view controllers. I.e. have the component acting as the delegate be created at application launch, and keep it alive. Then you can be sure to always receive all onIncomingMessage:, and you can also place logic for persisting messages there.
I am not sure if this is possible, but I need to grab all of the push notification userinfo when the user opens up the App. I can get all of the push notification userinfo when the App is opened or in the background, but not when the App is completely closed. Any way around this? The code below is how I get the userInfo currently.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
id data = [userInfo objectForKey:#"data"];
NSLog(#"data%#",data);
}
Unfortunately, it's not currently possible client side with that method to query old notifications that have occurred while the app was completely closed. See this question: didReceiveRemoteNotification when in background.
A way around it is to keep track of which notifications you send from your server per user. When didReceiveRemoteNotification: is called, you can take that notification and compare it against the server's messages for the current user. If one of them matches, mark it some way on the server. That way, if there are messages sent when your app is backgrounded, you can query for messages that haven't been marked from the server and get all 'missed' notifications.
The method you are implementing cannot handle both cases. See the "Local and Push Notification Programming Guide":
If your app is frontmost, the application:didReceiveRemoteNotification: or application:didReceiveLocalNotification: method is called on its app delegate. If your app is not frontmost or not running, you handle the notifications by checking the options dictionary passed to the application:didFinishLaunchingWithOptions: of your app delegate...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Notifications
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo){
//open from notification message
}
return YES;
}
You can add this code to your AppDelegate's applicationWillEnterForeground method:
-(void)applicationWillEnterForeground:(UIApplication *)application {
// this method is called when staring an app that was closed / killed / never run before (after applicationDidFinishLaunchingWithOptions) and every time the app is reopened or change status from background to foreground (ex. returning from a mobile call or after the user switched to other app and then came back)
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
NSLog(#"AppDelegate-getDeliveredNotificationsWithCompletionHandler there were %lu notifications in notification center", (unsigned long)[notifications count]);
for (UNNotification* notification in notifications) {
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo) {
NSLog(#"Processed a notification in getDeliveredNotificationsWithCompletionHandler, with this info: %#", userInfo);
[self showPushNotificationInAlertController:userInfo]; // this is my method to display the notification in an UIAlertController
}
}
UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
}];
}
}
Remove this line from the method application didFinishLaunchingWithOptions: if you had included it there, because it clears the badge number and also all notifications in notifications center:
UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
This is currently working in iOS 12, hadn't had the chance to test it in earlier versions.
My App receives APNS Push Notifications, and when a user receive more than one NSNotification, he should be able to open the app in a specific view according the NSNotification tapped.
So in the method
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler
I added this code to save all the notifications
if (self.notifications == nil) {
self.notifications = [[NSMutableArray alloc] init];
}
[notifications addObject:userInfo];
And every time the app becomes active again it does this
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started)
// while the application was inactive.
// If the application was previously in the background,
// optionally refresh the user interface.
[notifications removeAllObjects];
application.applicationIconBadgeNumber = 0;
}
Before removing all the objects and setting the badge to zero, I would like to handle which NSNotification made my app open from the background. And once I have which push NSNotification it was, I would like to pass all the data to a specific view.
Based on your comment about UILocalNotification usage
UILocalNotification has a userInfo property. When you create your local notification from the push notification, set the appropriate information into this property and then when the app delegate receives application:didReceiveLocalNotification: you can use that into to update your UI.
If you not use new iOS7 background fetch notifications.
In - (void)applicationDidBecomeActive:(UIApplication *)application before removing all object from notification array, check for notification
NSDictionary * myNotification = [notifications lastObject];
if (myNotification)
{
// is last notification
}
Is will work because app receive only notification that user tap on it
Send with your push notification, data, and use it when your app receives it.
In this example, i'm using the image file and alert, and sending it to all the views that are registered for this Notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
//Posting the notificaiton to the use, if its valid:
NSDictionary *returnDic = [userInfo objectForKey:#"aps"];
if (![returnDic objectForKey:#"alert"]) {
return;
}
NSString *alert = [NSString stringWithFormat:#"%#",[returnDic objectForKey:#"alert"]];
if (![returnDic objectForKey:#"MagnetID"]) {
return;
}
NSString *magnetImage = [returnDic objectForKey:#"MagnetImage"];
NSDictionary *dictionaryToSend = [NSDictionary dictionaryWithObjectsAndKeys:magnetImage,MAGNET_IMAGE,alert,MAGNET_ERROR_MESSEGE, nil];
//Posting to the rest of the views, the messege:
[[NSNotificationCenter defaultCenter] postNotificationName:USER_MESSEGE_RECEAVED object:nil userInfo:dictionaryToSend];
NSLog(#"Notifications - userInfo=%#",userInfo);
}
What you may do, is save the data that you need, by UserDefults or whatever you prefer, and at the "applicationDidBecomeActive" method, use that data to show the right view.
Hope this helps
It could be a possible duplicate link of.
Remove single remote notification from Notification Center
According to this post we can't delete single notification from notification center(NC).
For canceling notification we have below methods.
1).cancelAllLocalNotifications : it remove all notification.
2).cancelLocalNotification : it require notification as input.
I tried both methods, using first one it remove all notification from NC and the second one not seems work.
Here is the second snippet which I am applying on didRecivedRemoteNoitification method.
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSLog(#"userInfoCurrent : %#", userInfoCurrent);
int notiid=[[userInfoCurrent valueForKey:#"notificationID"] intValue];
if (notiid ==deletenotiid)
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
So my question is I am seeing couple of application that remove the tapped one notification from NC for example skype
Is there something which I am missing to apply.
Thanks for your valuable time.
You wrote that you included the above code in didRecivedRemoteNoitification. However, didRecivedRemoteNoitification is called only when a push notification arrives while the app is running in the foreground, in which case no notification is displayed and there is nothing to clear.
For notifications that arrive while the app is not running, when a user taps the notification, the notification data is passed to application:didFinishLaunchingWithOptions:. I think the tapped notification will be cleared if you clear the badge number.
- (void)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)opts {
// check launchOptions for notification payload and custom data, set UI context
[self startDownloadingDataFromProvider]; // custom method
app.applicationIconBadgeNumber = 0;
// other setup tasks here....
}