UILocalNotification Demystified

UILocalNotification is the simplest way to set up alerts in iOS. However, it may be difficult to get it to behave as you want.

 

During my recent experience from developing the Due? Done! app for iPhone, I needed to create alerts for due tasks, which required using UILocalNotification. If you do not understand how it behaves, it is very difficult to get it right.

 

To setup a local notification, all you need is something like

UILocalNotification* localNotification = [[UILocalNotificationalloc] init]; 
localNotification.fireDate = [NSDatedateWithTimeIntervalSinceNow:30];
localNotification.alertBody = @"Alert message goes here";
localNotification.timeZone = [NSTimeZonedefaultTimeZone];
[[UIApplicationsharedApplication] scheduleLocalNotification:localNotification]; 

 

This is the most simplest form of setting up a local notification in iOS. It schedules an alert after 30 seconds from now. You will get something like the following alert message when it fires.

The top line is the name of your app. In my case, my app is called "LocalNotification", so it displays "LocalNotification" as the header. The alert message (i.e. "Alert message goes here") is shown in the middle. It supports multiple lines by using the new line character (i.e. "\n"). The bottom part contains the default buttons (i.e. "Close" and "View").

 

In iOS5, the alert message is a bit different. It will look something like the following.

However, all the details are there with the exception of those buttons. If you tap on the alert, it will trigger the launching of the application.

 

All is going well... Right?

 

 

The mystery starts here

You may or may not get this alert message. It depends on whether your app is running and in which state, e.g. active in the foreground, active in the background, or not running at all.

According to the documentation

If the application is not frontmost and visible, the system displays the alert message, badges the application, and plays a sound whatever is specified in the notification.

If the application is foremost and visible when the system delivers the notification, no alert is shown, no icon is badged, and no sound is played.


It means that iOS will deliver the notification either visually or programmatically.

 

 

Delivering the Notification Programmatically

If your app is currently running and active (i.e. visible), you will not see the alert message. Instead iOS will deliver the notification to your app directly through the following method

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification


It is up to your app to show it or swallow it entirely.

 

 

Delivering the Notification Visually

If your app is not active (i.e. not running or in background state), iOS will show the alert message and allow the user to dismiss it or take action and launch your app. In the latter case, your app will run and be put into the foreground, i.e. visible.

Your app will be informed in one of the following two different ways. It depends on if iOS needs to launch your app or bring your app back to visible from background state.

Launching the app if the app is not running

The default didFinishLaunching method will be called with the notification object.

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

 

You can use the following key to retrieve the notification object from the launchOptions

UIApplicationLaunchOptionsLocalNotificationKey

 

Bringing the app back to foreground if it is in the background state

After bringing your app back to visible, the following method will be called with the notification object.

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification

 

 

Other Usages

The UILocalNotification is not simply just displaying a message. You can configure it to play a sound or update the badge number of you app etc...

 

For example,

Playing a sound

UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:30];
localNotification.alertBody = @"Alert message goes here";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 

 

Updating the badge number of the app

UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:30];
localNotification.applicationIconBadgeNumber = 2;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

 

Repeating the notification, say every hour

UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:30];
localNotification.alertBody = @"Alert message goes here";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.repeatInterval = NSHourCalendarUnit;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

You can mix and match the message, sound and badge. It is up to the situation that makes sense to your app and to your users.

 

Pushing your own data into the notification

You can even put some custom data into the notification object by using the userinfo, e.g. putting an ID to the notification.

NSDictionary *infoDict=[NSDictionary dictionaryWithObject:@"1234" forKey:@"IDkey"];
localNotification.userInfo = infoDict

 

 

Cancelling notifications

If your app requires cancelling any scheduled notification or notifications, you can do it by either

Cancelling all notifications that are associated to your application

You can use the following method to cancel all scheduled notifications

[[UIApplication sharedApplication] cancelAllLocalNotifications];

 

Cancel a particular notification

The iOS allows cancelling a specific notification using the following method, but you have to somehow obtain the notification object first.

[[UIApplication sharedApplication] cancelLocalNotification:localNotification];

 

The question is how to retrieve the correct notification object that we want to cancel.

Retrieve existing scheduled notification

You can get all scheduled notifications associated to your app, and then walk through them to identify the one (e.g. using the an ID you set it before) you want to cancel.

NSArray* localNotifications = [[UIApplication sharedApplication] 
scheduledLocalNotifications];
for (UILocalNotification *notification in localNotifications)
{
NSString* notificationID = [notification.userInfo objectForKey:@"IDkey"];
if([notificationID isEqualToString:@"1234"])
{
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}

 

 

References

  • My recent app that uses notifications to alert users of their due tasks.

Due? Done! for iPhone - http://jkq.com.au/duedone.html

  • UILocalNotification Class Reference

http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Reference/UILocalNotification_Class/Reference/Reference.html