Handling user acting on UILocalNotification - ios

My goal is to open a specific screen when user clicks on a UILocalNotification from the iOS Notification Center.
Now if the app is being resumed from the background when user acts on the Notification, I notice didReceiveLocalNotification is called:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
Now I can get the userInfo dictionary from the UILocalNotification object and opens the proper screen.
Unfortunately, this same method is called also when my app publishes a UILocationNotification while the app is running in the foreground:
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
How would I distinguish between the 2 cases?

It passes to you the application object that contains the state in its .applicationState property.
Consequently, you can make sure it is not active by testing...
if (application.applicationState != UIApplicationStateActive){
// do your stuff
}
And that's it!

Related

iOS: Programmatically dismiss a notification that is displayed on lock screen?

Imagine this: A user sees a notification on their lock screen e.g. "your server is online". Then something changes e.g. the server goes offline. Can I programmatically remove that notification (dismiss it) from the background even after it has been displayed on the lock screen?
Yes you actually can do this, you typically see it in action in messenger apps or social networking apps, for example, in some messenger app that has a web version, if you receive a message and you read it from the web but you already have received the push on your iOS app, when this happens you must send another push without display message, but a tag with value that indicates whatever you want:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if([[userInfo objectForKey:#"reset"] boolValue]){
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
}
}
This is a silent push notification.

Detect user tap on local notification

I show my local notification like this periodically.
UILocalNotification *notification = [[UILocalNotification alloc]init];
[notification setAlertBody:#"Test test"];
[notification setUserInfo:#{#"test": #"test"}];
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
I need to detect back that notification and I plan to write here.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
It always call that function whether user tap on notification or it automatically call in foreground.
So, I separate using this.
if (application.applicationState == UIApplicationStateActive)
When I show notification center, it become InActive. But, it still call didReceiveLocalNotification. I can't differentiate whether user tap on notification from notification center or because of my periodic posting notification.
How can I really know that I tap on notification (Either from InActive State or Background State) in didReceiveLocalNotification?
Assuming that I understood your issue correctly, I stumbled on the same obstacle and couldn't find a super clean solution.
So the situation where the following method
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
is called and applicationState is equal to UIApplicationStateInactive happens in two cases:
the app is in the foreground and the notification has just been fired
the notification has been fired some time ago, notification center is pulled down and user tapped on the notification
One way to distinguish these two cases is to check the notification's fireDate:
notification.fireDate.timeIntervalSinceNow < 0.5
If this expression is true, it's very likely that the first case happened. If the expression is false, it's very likely that the second case happened.
This solution depends on the system delivering the notification without delay and/or the user not being fast enough to click the notification in the notification center under 500ms since the notification's firing. I'm not sure how likely is it for a firing delay to happen. I guess it's possible if the device is under some kind of processing load.
I hope there is a cleaner solution, hopefully someone will share it.
First of all, read this from Apple Documentation:
The user taps a custom action button in an iOS 8 notification. In this
case, iOS calls either
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
or
application:handleActionWithIdentifier:forLocalNotification:completionHandler:.
In both methods, you get the identifier of the action so that you can
determine which button the user tapped. You also get either the remote
or local notification object, so that you can retrieve any information
you need to handle the action.
The user taps the default button in the alert or taps (or clicks) the
app icon. If the default action button is tapped (on a device running
iOS), the system launches the app and the app calls its delegate’s
application:didFinishLaunchingWithOptions: method, passing in the
notification payload (for remote notifications) or the
local-notification object (for local notifications). Although
application:didFinishLaunchingWithOptions: isn’t the best place to
handle the notification, getting the payload at this point gives you
the opportunity to start the update process before your handler method
is called.
Second, this is how you can differentiate whether didReceiveLocalNotification: is called from active or inactive state:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplicationState appState = UIApplicationStateActive;
if ([application respondsToSelector:#selector(applicationState)])
appState = application.applicationState;
if (appState == UIApplicationStateActive)
{
}
else
{
}
}
application:didReceiveLocalNotification:
Sent to the delegate when a running app receives a local notification.
Check this:
iOS UILocalNotification - No delegate methods triggered when app is running in background and the icon is clicked upon notification
Use KVO key-value-observing to know and do something when the button is tapped.

Cancel LocalNotifications method not executing when user closes/exits the app

I'm testing this on iOS 8.4 on Xcode simulator and on an iPhone 6. My notifications work fine and fire perfectly. But I can't figure out how to cancel the notifications when the user quits/closes the app. Pressing home button should NOT cancel the notifications and should still fire the notification.
This is what I have tried.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
return YES;
}
[[UIApplication sharedApplication] cancelAllLocalNotifications];
For the below method - it cancels the notifications when user presses Home button but or closes the app which is not what I want.
- (void)applicationDidEnterBackground:(UIApplication *)application
For below method - notifications will not cancel for home button or closing the app.
- (void)applicationWillEnterForeground:(UIApplication *)application
For below method - it does not execute the method at all for home button or closing the app.
- (void)applicationWillTerminate:(UIApplication *)application
I have looked into other similar questions posted on stack overflow but can't seem to get any of those suggestions to work. Please advise.
Once you fire the Notification it will be registered in the OS. OS presents the notification in time. You cant delete the notification after the application is terminated. No method will be called at the time of Termination.
When a notification arrives if your app is in foregroung didReceiveLocalNotification method will be called.
If you are in background DidLaunchwithOption method is called.
If the app is terminated no method is called.
You fire silent notification and present the actual notifications when you receive silent notifications in these methods. You can use userinfo to identify your notifications.
(void)applicationDidEnterBackground:(UIApplication *)application
Transitioning to the background, i.e when Home Button is pressed.
(void)applicationWillEnterForeground:(UIApplication *)application
Called when transitioning out of the background state
(void)applicationWillTerminate:(UIApplication *)application
Called only when the app is running. This method is not called if the app is suspended.
So, you won't be able to cancel notification, when app is about to be terminated. Therefore, you should choose some other mechanism to delete the Local Notifications. Like create a button to cancel all notifications or something like that.

Handling local notifications when the user presses the icon instead of the alert

Here is the situation that I want to handle quoted from Apple's documentation.
As a result of the presented notification, the user taps the action button of the alert or taps (or clicks) the application icon.
If the action button is tapped (on a device running iOS), the system launches the application and the application calls its delegate’s application:didFinishLaunchingWithOptions: method (if implemented); it passes in the notification payload (for remote notifications) or the local-notification object (for local notifications).
If the application icon is tapped on a device running iOS, the application calls the same method, but furnishes no information about the notification . If the application icon is clicked on a computer running OS X, the application calls the delegate’s applicationDidFinishLaunching: method in which the delegate can obtain the remote-notification payload.
How do I handle this situation if there is no information about the notification?
If I understand you correctly, it sounds like you have a UILocalNotification that has been fired, but you need to still handle it if the user taps the application icon instead of the notification. Correct?
If this is the case, then to my knowledge you won't be able to handle the notification from the app delegate, because the app is not being launched or brought out of the background by the notification, but instead by the user's interaction.
However, if you are setting a badgeNumber on the application with the notification then you could try something like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
} else if ([UIApplication sharedApplication].applicationIconBadgeNumber > 0) {
// Assume that user launched the app from the icon with a notification present.
}}
You may also have to check the badgeNumber in - (void)applicationDidBecomeActive:(UIApplication *)application as well.
Improve to #Aron Crittendon answer:
Consider also to handle that in applicationDidBecomeActive:
-(void)applicationDidBecomeActive:(UIApplication *)application
{
if ([UIApplication sharedApplication].applicationIconBadgeNumber > 0) {
//application is in background, fired notification and user tapped app icon with badge
}
}
As the documentation states, if you tap the icon on iOS (and not the notification's alert/banner) then the same method is called but you get no notification information. There is no way to handle a local notification simply by tapping the app icon.

Remove single remote notification from Notification Center

my app receives remote notification from Apple server.
Is there a way to remove a single remote notification from notification center (the drop-down menu available from iOs 5.0+), when the user taps on it?
Thanks!
There is no way to remove a specific notification as of iOS SDK 5.0. The way to remove all the notifications from your app so they don't show in the Notification Center when the user opens the app from one of them, is to set the app badge to 0, like this:
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
EDIT: on iOS 8, SpringBoard seems to be automatically dismissing a notification when you tap on it on the Notification Center to open the app.
Here is a suggestion, though it does have its flaws, and I haven't tried it myself:
Push a silent notification (contentAvailable:true), don't include a "alert" inside the push, place the alert text in a custom property of the push
Handle the incoming push and trigger a local notification, display it immediately
If the user clicks the local notification, use the [UIApplication cancelLocalNotification:] which should remove the notification from the notification center.
When you call the method:
[application cancelAllLocalNotifications];
inside the AppDelegate methods:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
All Local and Push Notifications will be remove on that for the particular app.

Resources