I have some UILocalNotifications in my app. When I receive one while I am in the app or if I press on the notification banner from the block screen or when it appears, the didReceiveLocalNotification works just fine. However, if I do not use the application and if I press on the icon of it (not on the banner) after notification banner appeared, the didReceiveLocalNotification method is not being called.
What should I do in this case, if I still want receive information about local notifications? Can I get it somehow in the applicationDidBecomeActive: method for example?
If you're app is completely shut down and you open it with a local notification, your local notification info will be passed into application:didFinishLaunchingWithOptions:.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification)
{
// Do whatever
}
// ...
}
Related
The problem:
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
is not called sometimes with iOS7.
It doesn't mater how we schedule the notification:
alarm.fireDate = [[NSDate date] dateByAddingTimeInterval:0.1];
[app scheduleLocalNotification:alarm];
or:
[app presentLocalNotificationNow:alarm];
My thoughts:
This happens in the case when the user slides before the notification alert animation is finished.
And if he waits just a half second before he slides - the notification is fired and the App proceeds as expected.
The problem probably is that application enters foreground before the notification is received.
Did anyone meet this? Is it a bug? Any solution? Thank you!
Is your application in the background or foreground? If it's in the foreground, I'm pretty sure that method is called. If it isn't, maybe you aren't putting that method in your application delegate.
If it's on the background, here's a few possible scenarios:
Your app has been killed by the user or the OS. In this case when the user wake up your app by tapping on the notification on the notification centre (or swiping in lock screen), your application delegate will have the application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method called. You can get the notification from this method by:
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
Your app is in background, and the user tap on the notification in notification centre or lock screen. In this case, no delegate methods will be called. The documentation specifically said that didReceiveLocalNotification: is for when the app is in the foreground:
If the app is running in the foreground, there is no alert, badging,
or sound; instead, the application:didReceiveLocalNotification: method
is called if the delegate implements it.
So hopefully you can make an informed decision about what to do when you receive the notification. I personally find it a little bit weird that we don't get the notification object when the user launches the app by tapping the icon (not the notification). But I currently just write my logic around it.
Apple explicitly mentions in their documentation (Local and Remote Notification Programming Guide) that different methods get called depending on what state the app is in and what action the user takes (as Enrico mentioned).
Summary:
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. ... 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). ...
The notification is delivered when the app is running in the foreground. The app calls the UIApplicationDelegate method application:didReceiveLocalNotification: or application:didReceiveRemoteNotification:fetchCompletionHandler:.
So didReceiveLocalNotification is only fired when the app is already running and is in the foreground. You should also handle the second scenario where the isn't running, for which apple has the following code example:
Objective-C:
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
NSString *itemName = [localNotif.userInfo objectForKey:ToDoItemKey];
[viewController displayItem:itemName]; // custom method
app.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;
}
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
Swift (approximation provided by myself):
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if let localNotification = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {
if let itemName = localNotification.userInfo?[ToDoItemKey] as? String {
handleNotification(localNotification)
application.applicationIconBadgeNumber = localNotification.applicationIconBadgeNumber - 1
}
}
.
.
.
}
I was trying to fetch remote notification info when the app was not running,so I was told that I can get from :
UILocalNotification *localNotification = [launchOptions
objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]
in method:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
,but still can't get info.
Then I use alertView to show the info on iPhone(launch without Xcode),still can't get the info.
Any other issue would cause this? Please let me know if you have any ideas.
How to retrieve and handle remote notifications:
app is running
The userInfo in below method already includes the push notification
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
app not running
The value for key in launchOptions includes the push notification,under two circumstance:
1.screen is locked,when receive the remote push notification,screen is lighted and user unlock the screen then directly launch the app.
2.user tap on the notification on the drop-down menu to launch the app.
If user tap on the app directly,then the notification will be gone and missed.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey] description];
}
That key is only in the launch options when the user starts your app from the notification (e.g. taps on it in notification center). Incidentally, I don't think a remote notification would be the class you're using (UILocalNotification).
If your app wasn't in the foreground when the device received the push, and the user didn't launch your app from the notification, the notification is gone. You have to check your own servers to see if you missed anything.
When my app is in minimized state and when that time push notification alert comes with two buttons close and view. I want to open particular screen in app when user click view button on alert.
When app is open state that time I can handle push notification by using below method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
If any one knows how to handle push notification alert buttons when app is in minimized state please help me. Thanks in advance.
Yeah
When The App is brought into running state via Notifications..This method is fired
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
You can then retrieve the notification received from the launchOptions dictionary and open the appropriate screen.
With iOS 5, push notifications can appear as banner and disappear after a few seconds.
I understand that didReceiveRemoteNotification will be called when user taps on the banner.
My question is, if the banner has disappeared and my user sees that there is a badge number on the app, they will tap on the app icon to start the app. Now if the app is running in the background, how do I check that the app is brought to foreground and there has been a notification, and do the necessary?
The purpose of my notification is basically to inform user there has been an update to the app content and encourage them to run the app to get the latest contents. My app only checks for latest contents at launch time and doesn't check for updates periodically.
This question is a bit old, but I'll pop what I've found in here anyway.
There are two methods you need to implement in your app delegate to check if your app was either launched from the remote notification (From when the app is not running on your device), or received the remote notification while running (in the background or foreground).
First is a method that is already in your App Delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
To check if this was launched from a remote notification, have some code similar to this:
// Check to see if launched from notification
if (launchOptions != nil)
{
NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
NSLog(#"Launched from push notification: %#", dictionary);
// DO SOMETHING HERE
}
}
The other method you will need to implement is specifically for the case that your application for when your application is running:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"Received notification: %#", userInfo);
}
How you handle the notification from there is up to you, but that's how your app knows about it!
In this second method, you can check the UIApplicationState of the passed application to find out if you were in the foreground or background.
I'm making an app that keeps track of some reminders that repeats with an user defined interval.
I've made it so when the alert displays, the action title says "Renew". When you click this, the app opens, and here I want to create the next reminder, but the problem is that I don't know if the app opens because the notification button was tapped or if the notification fired while the app was running.
Anyone got any ideas?
The 'correct' way to do this is to examine your NSApplication's applicationState property in the application:didReceiveRemoteNotification: method of your delegate.
From the documentation for handling local notifications:
iOS Note: In iOS, you 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. In the delegate’s implementation of
the application:didReceiveRemoteNotification: or
application:didReceiveLocalNotification: method, get the value of the
applicationState property and evaluate it. If the value is
UIApplicationStateInactive, the user tapped the action button; if the
value is UIApplicationStateActive, the application was frontmost when
it received the notification.
This is similar to your solution using flags set in applicationWillEnterForeground and applicationDidBecomeActive but with system support.
I don't know if my question was unclear but it seems that I got 4 different answers that all misinterpreted my question :P
However, I discovered that the didReceiveLocalNotivication happens between willEnterForeground and didBecomeActive, so I did this to determine if the app was already open or not:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSLog(#"Opened from notification? %#", wasInactive ? #"yes!" : #"no!");
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
wasInactive = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
wasInactive = NO;
}
Look up the documentation for UIApplication launch option keys. The last parameter to your application:didFinishLaunchingWithOptions: delegate method contains the information you need.
Also, look at application:didReceiveLocalNotification.
You're looking for
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
or
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
Documentation
If your application is already running you'll get this delegate message on the app delegate
application:didReceiveLocalNotification:
If it wasn't running you'll have to use
application:didFinishLaunchingWithOptions:
You need to respond appropriately in both methods to cover all cases
UPDATED
To detect if the user activated the action button requires a little more complexity. We can tell that application:didFinishLaunchingWithOptions: will have the local notification as a launch option, but it's more difficult with the application:didReceiveLocalNotification:.
Since the application becomes active after the user taps the button, we have to defer until we see that message (or not). Set an NSTimer in application:didReceiveLocalNotification and cancel it in didBecomeActive. That means the user pressed the action button. If the timer isn't cancelled the user was inside the app when it fired.
In your app delegate in this method:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
You have to examine the launchOptions looking at this key:
UIApplicationLaunchOptionsLocalNotificationKey
When you are already active this will be called:
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification