My app allows users to set a number of reminders in the future. When the app lauches I want to know what reminders (notifications) have already been set.
Can I read back the notifications I have set or do I need to store in my app (e.g. Core Data or Plist)?
UIApplication has a property called scheduledLocalNotifications which returns an optional array containing elements of type UILocalNotification.
UIApplication.shared.scheduledLocalNotifications
For Swift 3.0 and Swift 4.0
don't forget to do import UserNotifications
This is working for iOS10+ and watchOS3+ since the class UNUserNotificationCenter is not available for older versions (link)
let center = UNUserNotificationCenter.current()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
center.getPendingNotificationRequests { (notifications) in
print("Count: \(notifications.count)")
for item in notifications {
print(item.content)
}
}
}
Scott is correct.
UIApplication's property scheduledLocalNotifications
Here's the code:
NSMutableArray *notifications = [[NSMutableArray alloc] init];
[notifications addObject:notification];
app.scheduledLocalNotifications = notifications;
//Equivalent: [app setScheduledLocalNotifications:notifications];
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;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;
for (UILocalNotification *localNotification in arrayOfLocalNotifications) {
if ([localNotification.alertBody isEqualToString:savedTitle]) {
NSLog(#"the notification this is canceld is %#", localNotification.alertBody);
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
For more info, check out this: scheduledLocalNotifications example UIApplication ios
#Scott Berrevoets gave the correct answer. To actually list them, it is simple to enumerate the objects in the array:
[[[UIApplication sharedApplication] scheduledLocalNotifications] enumerateObjectsUsingBlock:^(UILocalNotification *notification, NSUInteger idx, BOOL *stop) {
NSLog(#"Notification %lu: %#",(unsigned long)idx, notification);
}];
Swift 3.0.2:
UIApplication.shared.scheduledLocalNotifications
In iOS 10, using the new UserNotifications framework:
UNUserNotificationCenter.current().getPendingNotificationRequests { (notificationRequests) in
print("Requests: \(notificationRequest)")
}
Swift 4
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (requests) in
for request in requests {
if request.identifier == "IDENTIFIER YOU'RE CHECKING IF EXISTS" {
//Notification already exists. Do stuff.
} else if request === requests.last {
//All requests have already been checked and notification with identifier wasn't found. Do stuff.
}
}
})
I used this to fix a bug where the same weekly notification was already set and being set again when the app would open, so it would keep resetting the timer to appear, which means it never did appear.
In Swift, to see all your currently scheduled local notifications printed in the console:
print(UIApplication.sharedApplication().scheduledLocalNotifications)
Related
Is there way to send local notification to the app from the app?
I need to send notification my app users every morning. So, can I add some code to the app, so after user launch that, every morning he or she will get badge/notification?
You can add local notifications to your iOS app by doing the following:
Step One
Register for local notifications in your App Delegate:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Register the app for local notifcations.
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
}
// Setup the local notification check.
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
// Check if a notifcation has been received.
if (notification) {
dispatch_async(dispatch_get_main_queue(), ^{
// Run the notifcation.
// Call your own custom method from here.
// Use [notification.userInfo valueForKey:#"notification_id"] to get the associated notification id (You will need to assign an ID, when creating the notification).
});
}
// Ensure the notifcation badge number is hidden.
application.applicationIconBadgeNumber = 0;
return YES;
}
Step Two
Use the following method to create the local notification:
-(void)saveNotification:(NSString *)description :(NSString *)notificationID :(BOOL)locationCheck {
// Create the notification info dictionary
// and set the notification ID string.
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
[userInfo setObject:notificationID forKey:#"notification_id"];
// Setup the local notification.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// Set the notification ID and type data.
localNotification.userInfo = userInfo;
// Set the notification description.
localNotification.alertBody = [NSString stringWithFormat:#"%#", description];
// Set the sound alert MP3 file.
localNotification.soundName = [NSString stringWithFormat:#"Notification_sound_file.mp3"];
// Set the date for the notification or set the
// location depending on the notification type.
if (locationCheck == NO) {
// Fire date of your choice.
NSDate *yourFireDate;
// Set the reminder date.
double interval = [yourFireDate timeIntervalSinceNow];
localNotification.fireDate = [[NSDate date] dateByAddingTimeInterval:interval];
localNotification.timeZone = [NSTimeZone systemTimeZone];
// Set the notifcation repeat interval.
localNotification.repeatInterval = 0; // No repeat.
//localNotification.repeatInterval = NSCalendarUnitHour; // Every hour.
//localNotification.repeatInterval = NSCalendarUnitDay; // Every day.
//localNotification.repeatInterval = NSCalendarUnitWeekOfYear; // Once a week.
//localNotification.repeatInterval = NSCalendarUnitMonth; // Once a month.
//localNotification.repeatInterval = NSCalendarUnitYear; // Once a year.
}
else if (locationCheck == YES) {
// Set the locaton to the selected address co-ordinates.
CLLocationCoordinate2D coordinates = CLLocationCoordinate2DMake(latitude, longitude);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinates radius:100 identifier:[NSString stringWithFormat:#"region_%#", notificationID]];
// Set the notification to be presented
// when the user arrives at the location.
[region setNotifyOnEntry:YES];
[region setNotifyOnExit:NO];
// Set the notification location data.
[localNotification setRegion:region];
[localNotification setRegionTriggersOnce:NO];
}
// Save the local notification.
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
You will need to create your own unique id, in order to use this method. The id is important, because it will help you to distinguish between notifications (should you need to perform a specific action depending on the notification).
You can call the above method like so:
[self saveNotification:#"test notification hello world" :#"unique id" :NO];
Don't forget to replace latitude and longitude with your descried co-ordianted (if you need location based local notifications).
Step Three
If the app is currently open (in the foreground or via multitasking), you will need to implement another method in your app delegate, in order to handle notifications:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
// Check if a notifcation has been received.
if (application.applicationState == UIApplicationStateInactive) {
// You app in running in the background but will be active,
// should the user tap the iOS notification banner.
// Call your own custom method from here.
// Use [notification.userInfo valueForKey:#"notification_id"] to get the associated notification id (You will need to assign an ID, when creating the notification).
}
else if (application.applicationState == UIApplicationStateActive) {
// The app is open in the foreground
// you will need to display an alert or banner
// in your app to alert the user.
// Call your own custom method from here.
// Use [notification.userInfo valueForKey:#"notification_id"] to get the associated notification id (You will need to assign an ID, when creating the notification).
}
// Ensure the notifcation badge number is hidden.
application.applicationIconBadgeNumber = 0;
}
A few other points to keep in mind
You can only set a maximum of 64 local notifications.
(Notifications which repeat are counted as one local notification). https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/
A local notification cannot have a fireDate and location region. If you want the same notification to appear at a given time and location, you will have to create 2 separate local notifications with the same description (one with a date and the other with the location).
You can use the following methods to delete all local notifications (or a specific one):
-(void)deleteAllNotifications {
// Delete all the local notifications.
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
-(void)deleteSpecificNotification:(NSString *)inputID {
// Get the notification(s) data.
NSArray *notificationData = [[UIApplication sharedApplication] scheduledLocalNotifications];
// Loop through all the local notifcations and delete
// all the notifications that match the input id string.
for (int loop = 0; loop < [notificationData count]; loop++) {
// Get the notification object.
UILocalNotification *localNotification = [notificationData objectAtIndex:loop];
// If the notification id matches the input id then delete it.
if ([[localNotification.userInfo objectForKey:#"notification_id"] isEqualToString:inputID]) {
[[UIApplication sharedApplication] cancelLocalNotification: localNotification];
}
}
}
I can't seem to find it and I'm not sure how to Google it. In my app I use background fetches to do checks and if there is new data, I send a notification to the user using UILocalNotification. Now how do I prevent the app from sending a new notification to the user if there is already one there? I'm now ending up with 5 of the same notifications when I don't look at my phone for some hours.
Thanks!
You can use UIApplication's property scheduledLocalNotifications
Here's the sample code:
NSMutableArray *notifications = [[NSMutableArray alloc] init]; [notifications addObject:notification]; myApp.scheduledLocalNotifications = notifications;
//Equivalent: [myApp setScheduledLocalNotifications:notifications];
UIApplication *myApp = [UIApplication sharedApplication];
NSArray *eventArray = [myApp scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[myApp cancelLocalNotification:oneEvent];
break;
}
}
NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;
for (UILocalNotification *localNotification in arrayOfLocalNotifications) {
if ([localNotification.alertBody isEqualToString:savedTitle]) {
NSLog(#"the notification this is canceld is %#", localNotification.alertBody);
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
Hope this would help figure out the solution.
The best way to avoid having to cancel something it in the first place is also to simply NOT sending it.
Find a way to know if the user has been notified before, and if he has, don't notify again :)
This is cleaner, more efficient, will last forever, and won't backfire, ever.
Also, this answers your question of "not sending a notification again" instead of sending it and cancelling afterwards, which isn't a good idea if you think about it.
I am working on a dummy project in xcode 6 and creating local notifications. I have created and deleted these local notifications.Now I want to edit a particular notification.
You cannot change an already scheduled notification.
You will have to cancel, and re-create it with the new data you need.
You can ask the current scheduled UILocalNotifications:
NSArray *scheduledNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
Loop the array and do a check if its the notification you need to change:
for (UILocalNotification *notification in scheduledNotifications)
{
//Get the ID you set when creating the notification
NSDictionary *userInfo = notification.userInfo;
NSNumber *someValueYouGaveWhenCreatingCouldBeAnIdentifierOfAnObject = [userInfo objectForKey:#"someKey"];
if (someValueYouGaveWhenCreatingCouldBeAnIdentifierOfAnObject == someCheckYouHaveToDoHere)
{
[[UIApplication sharedApplication] cancelLocalNotification:notification];
//Re-create the localnotification with new data and the someValueYouGaveWhenCreatingCouldBeAnIdentifierOfAnObject
break;
}
}
I'm currently trying to cancel specific UILocalNotifications associated with objects in my data model. To do this, each data object has a unique identifier, which is an NSUUID.
Create UILocalNotification:
/* Set UILocalNotification */
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = date;
localNotification.alertBody = self.mytextfield.text;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = 1;
NSLog(#"making a notification: %#",[r.uniqueId UUIDString]);
[localNotification.userInfo setValue:[r.uniqueId UUIDString] forKey:#"uid"];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
Yet when I go to delete the notification and print out each notifications contents, the alertbody of the notifications are printed correctly but the unique identifier is somehow lost. What's wrong with this implementation?
Cancel UILocalNotification:
Obj *r = (Obj *)[self.objects[indexPath.section] objectAtIndex:indexPath.row];
/* Cancel UILocalNotification */
NSArray *scheduleReminders = [[UIApplication sharedApplication] scheduledLocalNotifications];
NSLog(#"scheduled.count: %i",(int)scheduleReminders.count); // Correctly prints 3
for (int i = 0; i < scheduleReminders.count; i++)
{
UILocalNotification *notification = scheduleReminders[i];
NSDictionary *userInfoCurrent = notification.userInfo;
NSLog(#"searching through reminders: %i %# %# %#",(int)i,[userInfoCurrent objectForKey:#"uid"], notification.alertBody); // Alert body prints correctly
if ([[userInfoCurrent valueForKey:#"uid"] isEqualToString:[r.uniqueId UUIDString]])
{
NSLog(#"found it");
//Cancelling local notification
[[UIApplication sharedApplication] cancelLocalNotification:notification];
break;
}
}
The problem is that userInfo is "nil" by default. You should allocate your own NSDictionary, set uid and then set this dictionary to localNotification.userInfo.
I'm using a UILocalNotification object to give notification to my application. Currently each time an event is generated i popup a notification.
notification.alertBody=#"Event Occurs 2";
notification.alertAction=#"Open";
[[UIApplication sharedApplication]presentLocalNotificationNow:notification];
But, since the events keep on happening, each time a new notification is generated.
Is there a way to update a notification, if it is already present and create a new notification if not present.
You can't update an already scheduled Local Notication. You can however, cancel it and reschedule a new one.
Cancel your local notification:
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;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling the specific local notification
[app cancelLocalNotification:oneEvent];
//Schedule your new "updated" local notification here.
break;
}
}
This will loop through all scheduled local notifications and delete the local notification you want deleted. Note, you'll need to set a unique property to each notification to distinguish between others (in the example above, it is assumed userInfo contains a unique "uid").
Thanks to KingofBliss for code above on how to delete specific local notifications.
It's not possible to update the notification but if you attach a dictionary with a key to the alert:
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:alarmID forKey:#"AlarmKey"];
// Set some extra info to your alarm
notification.userInfo = userInfo;
Then you can retrieve the local notification, cancel it and make a new one with updated content.
+ (UILocalNotification *)existingNotificationWithAlarmID:(NSString *)alarmID
{
for (UILocalNotification *notification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
if ([[notification.userInfo objectForKey:#"AlarmKey"] isEqualToString:alarmID]) {
return notification;
}
}
return nil;
}
You cancel the notification like this:
- (void)cleanUpLocalNotificationWithAlarmID:(NSString *)alarmID
{
UILocalNotification *notification = [self existingNotificationWithAlarmID:alarmID];
if (notification) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
No, there is no way to modify a local notification that has been scheduled. You'll have to cancel the notification and schedule it again.