Reading through recent comments, a few of you have asked how to get local notifications working on your iOS apps. Local Notifications are the one that pop up on your lock screen and give you information such as when an alarm goes off or a calendar item becomes due. If you are using your iPhone, they also drop down from the top of the screen for a few seconds. Types of apps that use this feature could include calendars, todo lists, games and any other type of app that might want to inform a user that some action could be taken or that some information is available. An example of a local notification was used in the Background App Refresh tutorial recently. In todays tutorial, we’ll show you in more detail how this is done.
Local Notifications make use of a class called UILocalNotification in the UIKit framework. By configuring the properties of UILocalNotification, you can use the UIApplication class to trigger the notification to arrive on screen either immediately or at a specified time and date. UIApplication handles putting the notification on the screen when required.
Todays tutorial will be brief and will simply let you select a date and time to fire a notification. The code to achieve this can be implemented in many situations such as on a location based app that fires a notification when you enter within range of a recognised iBeacon or when you enter a specified region.
UILocalNotification Tutorial
Lets start by creating a Single View Application. When created, load up the Storyboard as seen on the image to the left.
When loaded up, we need to drag out a UIButton and a UIDatePicker. The button will be used to set the notification going and the UIDatePicker will be used to set the date/time that the notification should be fired. The layout is very simple the purpose of this tutorial:
Now that you have the UIDatePicker on screen, you need to make some tweaks to the settings using the inspector. To do that, click on the UIDatePicker to select it and then click to Show the Attributes Inspector as seen below:
Here we select Date and Time, Default Locale, Interval 1 minute, Date as current date and leave the rest as it is. Feel free to set this however you want. You can opt for 30 minute intervals if you wish. It’s up to you how you do this.
Next we need to show the Assistant Editor which allows us to see both the Storyboard and the Implementation side by side. This allows us to CTRL+Drag to connect up the IBActions that we need to allow the user to interact with the application.
CTRL+drag from the UIDatePicker to the implementation. I called the IBAction datePicker and selected UIDatePicker as the type.
Now do the same for the UIButton. I called it setNotification and set the type as UIButton.
We now need to implement the code that will make this work. Lets start with the datePicker method as we need to provide an NSDate to the UILocalNotification so that we can set when the notification will be fired.
1 |
NSDate *dateTime; |
1 2 3 |
- (IBAction)datePicker:(UIDatePicker *)sender { dateTime = sender.date; } |
The first line of code in the above block can go under the @implementation line. Declaring it here makes it accessible by other methods in this class.
The only line of code we need to add to the datePicker: method is to use the sender.date property and assign it to dateTime. The UIDatePicker provides an NSDate and the UILocalNotification requires an NSDate which makes this process simple.
Moving on to the setNotification: method, there are several lines of code that need adding so that we can configure the notification and tell it when to fire as well as tell it what should be displayed on screen.
1 2 3 4 5 6 7 8 |
- (IBAction)setNotification:(UIButton *)sender { UILocalNotification *localNotification = [[UILocalNotification alloc] init]; localNotification.fireDate = dateTime; localNotification.alertBody = [NSString stringWithFormat:@"Alert Fired at %@", dateTime]; localNotification.soundName = UILocalNotificationDefaultSoundName; localNotification.applicationIconBadgeNumber = 1; [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; } |
Line 2 we alloc/init a UILocalNotification.
Line 3 we set the fireDate property. We do that with the dateTime we collected from the UIDatePicker. The fireDate is exactly what it sounds like… the date that the notification will fire.
Line 4 we set the alertBody. This is the text that appears on screen in the notification (either on the lock screen or as a banner depending on if your phone is locked or unlocked). By default, the name of the alert will be the name of your app. The text can be whatever you want and formated with the class method stringWithFormat: so that you can pull in information such as the dateTime. If you were alerting about a calendar event or task you might want to pull in information such as the appointment name and time.
Line 5 we set the soundName property. Here we assigned that property the default sound name (the regular chime).
Line 6 isn’t really required here, but what you could do is set the applicationIconBadgeNumber. This needs to be an INT. Anything set here will display as a number in a red circle on the top right of the icon.
Line 7 is where we schedule the local notification. As we are using the UIApplication class as a sharedApplication, we first access that and then call the scheduleNotification: method on that.
The app is now ready to run. If you set up several alerts they will all be presented at the specified date and time. All notifications are queued up and fire at the times specified although note that if your app is currently running then triggered alerts will not show or make a sound. They are simply ignored under this configuration. We’ll take a look in a few moments how to get around that.
Lets now quickly look at the presentLocalNotificationNow: method in the UIApplication class. This method is different to the scheduleLocalNotification: method. As the name suggests, it fires the alert right now.
Uses for this would include entering a region and immediately notifying the user that they have entered a region on a map. When you enter a region, you don’t need to be alerted at a specific time… you need to be notified now. Using this method avoids you having to use an NSDate or setting the fireDate property as they are not needed and ignored.
Going back to my comment about notifications not showing when the app is running, we can actually address this using a delegate method in the AppDelegate as follows:
1 2 3 |
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { } |
If a notification fires when you are using the app, instead of being notified, the method above is called. At this point it is up to you how you inform the user that a notification has happened. Perhaps you will put a message on the screen or perhaps cause a UIAlert to show on the view. Either way, this delegate method lets you know what UILocalNotification was going to be presented and here you could get the alertBody by accessing notification.alertBody.
The full code of this project is below or can be downloaded here.
ViewController.h – No changes needed from default.
ViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#import "ViewController.h" @interface ViewController () @end @implementation ViewController NSDate *dateTime; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (IBAction)setNotification:(UIButton *)sender { UILocalNotification *localNotification = [[UILocalNotification alloc] init]; localNotification.fireDate = dateTime; localNotification.alertBody = [NSString stringWithFormat:@"Alert Fired at %@", dateTime]; localNotification.soundName = UILocalNotificationDefaultSoundName; localNotification.applicationIconBadgeNumber = 1; [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; } - (IBAction)datePicker:(UIDatePicker *)sender { dateTime = sender.date; NSLog(@"Date is %@", dateTime); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |
AppDelegate.m
Just implement the following delegate method:
1 2 3 |
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { } |
Scuzzy says
Great tutorial!
How would you go about canceling a queued notification? Say you set one for 10 days from now and you want to cancel or change it?
MatthewN says
This can be done by working with the scheduledNotifications property in the UIApplication class.
The scheduledNotifications property is an NSArray which contains all UILocalNotifications objects that have been scheduled. What you can do is find the appropriate UILocalNotification object within that NSArray and then use that UILocalNotification with the cancelLocalNotification: and specify the particular UILocalNotification.
To pull the correct UILocalNotification object from the NSArray you need to find something that matches such as a title so that you can find an NSString that matches. An easier way is to use the userInfo property of UILocalNotification and give each UILocalNotification a different and unique key. When querying you can then specify the key and enumerate through the NSArray to find what you are looking for.
If you want, you can also cancel all notifications by calling cancelAllLocalNotifications.
Making changes can be done a few ways. You can pull out the notification and cancel it and then recreate it with the new settings. Alternatively, you can make a copy of the NSArray in to an NSMutableArray and make the changes needed and then copy it back. There’s probably other ways, but these were the first ideas I came up with.
Manuj Bahl says
I am trying to use a UILocalNotification in my app and am running into an issue i dont understand.
The notification is setitng the badge id at teh correct time on my app icon, when the notification is not getting fired properly. I dont see the alert popup on the home screen or the lock screen when the app is in background or not running.
when the app is active i do get the didRecieveLocalNotification call.
my code looks like this
-(void) ScheduleLocalNotification
{
UIApplication* app = [UIApplication sharedApplication];
[app cancelAllLocalNotifications];
NSDate *now = [NSDate date];
notificationDate = [now dateByAddingTimeInterval:60*1];
// Schedule the notification
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = notificationDate;
localNotification.alertBody = @”Notification Body Text”;
localNotification.alertAction = @”Title”;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.applicationIconBadgeNumber = [app applicationIconBadgeNumber] + 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
[app scheduleLocalNotification:localNotification];
}
Krishnanunni says
What if the app is terminated? or How to notify a user even if the app is killed? I know it is possible for beacon ranging. Is it possible to notify a user for any other scenario, like a temperature alarm or a reminder ?
Matthew says
I haven’t checked those individually, so I would suggest putting together a quick test to see if local notifications do fire when the app is terminated.
kaykeat says
Simple and easy to follow :)
nikunj says
how do i change the text of alertbody when application is terminated .
Mohsin says
is this tutorial work on Simulator or not? I am facing this message in log “Attempting to schedule a local notification {fire date = Wednesday, December 30, 2015 at 4:16:23 PM Pakistan Standard Time, time zone = (null), repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Wednesday, December 30, 2015 at 4:16:23 PM Pakistan Standard Time, user info = (null)} with a badge number but haven’t received permission from the user to badge the application ” while running on simulator.
Matthew says
I haven’t tested in the simulator, but it should work in the simulator. I believe the issue is that this tutorial is for an older version of iOS. Since about iOS 8, Apple has required something extra be done to seek for permission from the user to pass notifications from them. I’ll find the code and amend it now and post back when completed.
Matthew says
You need to put this code, or some variation of it in the app delegate “didFinishLaunchingWithOptions:”. The code below checks to see if the iOS version requires permission to be needed (meaning, does it respond to the registerUserNotificaionSettings: selector) and if so, permissions are needed and it then seeks for permission from the user.
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
ABIN KOSHY CHERIYAN says
How to show a local notification without using any timer? For Eg: I am having transaction updates in background mode. Only when there is any transaction update, a notification needs to be displayed.
Ashish Garud says
I am using this code to schedule a local notification on specific date and time.But it is not working,It works only when i am selecting date and time less than current date and time.
Can any please give me solution on this:
UIApplication* app = [UIApplication sharedApplication];
[app cancelAllLocalNotifications];
localNotification = [[UILocalNotification alloc] init];
NSString *DateAndTime=[NSString stringWithFormat:@”%@ %@”,STARTDATE,TIME];
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@”GMT+0:00″]];
[formatter setDateFormat:@”YYYY-MM-dd hh:mm”];
NSDate *conDate=[formatter dateFromString:DateAndTime];
NSLog(@”%@”,conDate);
localNotification.fireDate=conDate;
localNotification.alertBody = NAME;
localNotification.alertTitle=me;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.soundName=UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
Rafiullah says
notification is trigger when the specified date and time is reached. now if u specify date and time greater than the current time then that time will never reached and the notification will not be executed.
Rafiullah says
how can we put a message on the screen i don’t understand what does it mean.