I need to clear already displayed local notification from Notification Centre programmatically. Following this link I implemented suggested solution, but the problem is that eventArray from this example always has 0 elements. When I swipe down to display Notification Centre I see 4 notifications that I've created previously. So in this case I expect this array to have 4 elements, but it has 0. Any idea why is this so? I've tried on iOS 8.3 and 9.2.1 and array is 0 on both of them.
iOS has 2 ways of presenting local notifications:
From Notification Center:
You can't swipe away notification from left to right.
You can swipe notification from right to left (deleting single notification from the list).
You can click on the notification, after which your app will start and notification will be removed from Notification Center (handled by iOS system)
From Lock screen:
Available only if you enable this setting from iPhone/iPad settings: http://www.imore.com/how-disable-notification-center-lock-screen-your-iphone-and-ipad
You can swipe notification from left to right (your app will be started, handled by iOS). In this case notification from Notification Center is not deleted (iOS doesn't delete it, and doesn't allow deleting a single notification from code after notification is already presented to the user in Notification Center).
You can swipe notification from right to left (deleting single notification from the list, handled by iOS. Notification Center notification is also deleted, handled by iOS).
You can't click on the notification.
EDIT:
Here is code sample how I did it:
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"1";
localNotification.alertTitle = #"1";
localNotification.userInfo = uniqueDictIdentifier1;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
UILocalNotification *localNotification2 = [[UILocalNotification alloc] init];
localNotification2.alertBody = #"2";
localNotification2.alertTitle = #"2";
localNotification2.userInfo = uniqueDictIdentifier2;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification2];
....
//2 more notifications are created like this
And then there is code for filtering all notifications:
NSArray *eventArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++) {
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
if ([userInfoCurrent isEqualToDictionary:uniqueDictIdentifier1]) {
[[UIApplication sharedApplication] cancelLocalNotification:oneEvent];
break;
}
}
For saving a notification for a unique id
NSDictionary * infoDict = #{ #"alarmUiqueId" : uID,
};
NSLog(#"%#",infoDict);
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitSecond
fromDate:fireDate];
fireDate = [fireDate dateByAddingTimeInterval:-comp.second];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
localNotif.fireDate = fireDate;
localNotif.timeZone = [NSTimeZone localTimeZone];
localNotif.alertBody = desString;
localNotif.userInfo = infoDict;
localNotif.repeatInterval = NSCalendarUnitDay;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif]
and for delete a paritcular notification write this code.
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
for(UILocalNotification *notification in notificationArray)
{
NSLog(#"%#",[notification.userInfo valueForKey:#"alarmUiqueId"]);
if ([[notification.userInfo valueForKey:#"alarmUiqueId"] isEqualToNumber: health.uniqueId])
{
[[UIApplication sharedApplication] cancelLocalNotification:notification] ;
}
}
My understanding is below:
You can not get the information of already notified LocalNotification with scheduledNotifications.
My resolution is that just keep UILocalNotification instance in your singleton object in your application, and call cancelLocalNotification with the instance when you want to delete from Notification Center.
Is this could be your help ?
Related
When I create my local notification callback didReceiveLocalNotificationgets triggered. The same callback gets triggered when I click on the local notification. Currently I was dividing those two cases by checking
if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
//this means notification is clicked
}
But the main problem here is that when you are in the foreground and you slide your notification menu, and then receive your local notification, this callback didReceiveLocalNotification gets called. And in this case my app goes into this if. Because of this, I can't really distinguish from clicking the notification and creating a local notification while app is in the inactive state. Any ideas on how can I fix this?
This is the code for scheduling a local notification:
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"aaaa";
localNotification.alertTitle = #"title";
localNotification.userInfo = myUserInfo;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
After calling this, I get didReceiveLocalNotification delegate triggered.
I had to work around the exact same issue in my app. I couldn't find an offical way in the API to tell the difference, but here is a workaround.
Pass the current date in the userInfo when the local notification is created:
localNotification.userInfo = ["alertDate": NSDate()]
And when you handle didReceiveLocalNotification, check against current date again, to make sure it didn't just fire just a moment ago:
if application.applicationState == .Inactive {
if let alertDate = notification.userInfo?["alertDate"] as? NSDate
where (NSDate()).timeIntervalSinceDate(alertDate) > 0.1 {
// this means notification was initiated by user
}
}
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
localNotification.alertBody = #"image inserted";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[self dismissViewControllerAnimated:YES completion:nil];
I am trying to set up an Apple Watch app (presenting flashcards) which fires a notification when a new question is due. If the iPhone is open but the app is in the background it fires a UIAlert, and clicking the action button ("View") opens the app. If the iPhone is locked the notification fires on the Apple Watch with a short glance-long glance with a button "View Question" which opens the Apple Watch app.
It works, but the UIAlert on the iPhone has an annoying "Options" button which requires you to click "Options" to open another UIAlert with two action buttons ("View" and "View Question"), either of which will open the iPhone app. Here is the relevant code which first cancels all previous notifications (as the app allows you to answer a new question before the timer is finished, at which point the timer is reset). It then sets up a notification to be displayed on the iPhone; and finally sets up a notification for the Apple Watch.
// Cancel previous notifications
[[UIApplication sharedApplication] cancelAllLocalNotifications];
// Set up iPhone notification
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:(int)dateLatency];
localNotification.timeZone = [NSTimeZone defaultTimeZone];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSInteger intVal = [prefs integerForKey:#"timeLag"];
localNotification.alertBody = [NSString stringWithFormat:#"%ld-%d", (long)intVal, (int)dateLatency];
localNotification.alertAction = [NSString stringWithFormat:#"View"];
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertLaunchImage = nil;
localNotification.category = #"qDue";
localNotification.userInfo = [self createAPNS:#"999"]; // function that constructs userInfo json structure
// Set up apple watch notification
NSMutableSet *categories = [[NSMutableSet alloc] init];
UIMutableUserNotificationAction *viewQuestion = [[UIMutableUserNotificationAction alloc] init];
viewQuestion.title = #"View Question";
viewQuestion.identifier = #"viewQuestion";
viewQuestion.activationMode = UIUserNotificationActivationModeForeground;
viewQuestion.authenticationRequired = false;
UIMutableUserNotificationCategory *questionCategory = [[UIMutableUserNotificationCategory alloc] init];
questionCategory.identifier = #"qDue";
[questionCategory setActions:#[viewQuestion] forContext:UIUserNotificationActionContextDefault];
[categories addObject:questionCategory];
UIUserNotificationType notificationType = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationType categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
// Schedule it with the app
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
I can get rid of the "Options" button and the extra UIAlert by deleting the apple watch notification, but then there is no notification on the apple watch.
Can anybody tell me why the "Options" button appears, and how to get rid of it?
I want to schedule local notification in my game.
First notification will come two hours after game play has ended.
After that another one come in the next 24 hours if still no gameplay. If gameplay resets to after 2 hours, then every 24 hrs until they enter game.
I would be very thankful to you if you can help me.
Here is my code:
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.alertBody = [self.notifyArray objectAtIndex:index];
NSTimeInterval sec = 7200;
notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:sec];
notif.repeatInterval = NSDayCalendarUnit;
notif.soundName = UILocalNotificationDefaultSoundName;
NSLog(#"notif : %u",notif.repeatInterval);
notif.applicationIconBadgeNumber += 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
//notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:20];
//[[UIApplication sharedApplication] scheduleLocalNotification:notif];
Try to debug first by checking the scheduled notifications list. You can see this thread for details iOS find list of Local Notification the app has already set
First give an 'identifier' to your local notification. Then and when app goes to background, use that identifier to identify notification from scheduled notifications of your application. And reschedule it after 2 hours , with repeat interval of day.
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
if ( oneEvent.identifier = yourNotificationIdentifier){
//Reschedule oneEvent.
}
}
In my app I have objects that trigger Local Notifications.
When the app is in the background the Local Notifications are fired when it's their time to be fired, and that works fine.
For some reason, the Badge Number is not updated.
When setting the Notification object, I use the following code:
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = obj.noteMeDate; //obj is an object for which the notification is created...
localNotification.alertBody = [NSString stringWithFormat:#"Note: %#", obj.title];
localNotification.alertAction = #"Show Me";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1; //this is NOT WORKING...
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
Anyone?
You can't increase the badge number, you can only set it to a certain number. At the time you're scheduling the notification, applicationIconBadgeNumber is 0 (since you're running the application in the foreground), thus every notification is showing only 1 in the badge.
Technically you cannot increment the badge icon directly but there is a way.
int num = [UIApplication sharedApplication].applicationIconBadgeNumber;
[UIApplication sharedApplication].applicationIconBadgeNumber = num + 1;
i am making reminder application there is table view and there is dates in cell and when that cell date become todays day UILocalNotification fires. for that i am using following code
-(void)notification {
// logic for local notification start
NSDateFormatter *Form = [[NSDateFormatter alloc] init];
[Form setDateFormat:#"dd/MM/yyyy"];
UILocalNotification *notification = [[UILocalNotification alloc] init];
for (int i=0;i<_convertedBdates.count;i++)
{
NSDate *date =[Form dateFromString:[_convertedBdates objectAtIndex:i ]];
// NSLog(#"date%#",date);
if(notification)
{
notification.fireDate = date;
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = [NSString stringWithFormat:#"Today is %#\'s Birthday",[_combinedNameArray objectAtIndex:i]];
notification.alertAction = #"View";
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
// local notification logic ends here
}
now i have also implemented functionality of deleting cell from table view
now my problem is cell gets removed but its notification not there is no cell but when that date comes then notification fire.
how should i remove that particular notification when that cell is removed?
Edited: My initial answer was wrong, because I didn't realize that the OS copies UILocalNotifications when you schedule them, rather than just retaining them. So...
There are two ways to do this, as far as I can tell.
Cancel all notifications when a row is deleted, and then reschedule the remaining ones.
This is going to be more efficient if you don't have many notifications scheduled, and it will definitely be much easier to code. (Note: I don't know enough about the low-level things at work to say which is necessarily more efficient, but my guess is that the difference isn't really important.)
Whenever a row is deleted, simply call
[[UIApplcation sharedApplication] cancelAllLocalNotifications];
Then update _convertedBDates appropriately, and finally call your notification method again to reschedule new local notifications for those events that are still around.
Create unique identifiers for your local notifications
This is possibly the more efficient way, if you can come up with a good way to make those unique identifiers and if you have a lot of notifications scheduled. (Emphasis on possibly). One possibility is to use the time at which the notification will fire, if you can guarantee that no two notifications will fire at the same time. Other possibilities are the label for the notification (again if you can be sure of uniqueness). Whatever you decide to use for your unique identifier, you can store it by adding this outside your for loop:
self.uniqueIDArray = [[NSMutableArray alloc] init];
(where uniqueIDArray is an NSMutableArray* #property of your class) and then this right before you schedule the notification:
[uniqueIDArray addObject:whateverObjectYouUseForTheUniqueID];
notification.userInfo = [[NSDictionary alloc] initWithObjects:whateverObjectYouUseForTheUniqueID
forKeys:#"uniqueID"];
Then, in whatever method you're using to delete the cells, you would do something like this:
uniqueIDToDelete = [self.uniqueIDArray objectAtIndex:indexOfCellBeingDeleted];
NSArray *scheduledNotifications = [[UIApplication sharedApplication] scheduledNotifications];
UILocalNotification *notifToDelete;
for (UILocalNotification *notif in scheduledNotifications) {
if ([[notif.userInfo objectForKey:#"uniqueID"] isEqual:uniqueIDToDelete]) {
[[UIApplication sharedApplication] cancelLocalNotification:notif];
}
}
[self.uniqueIDArray removeObjectAtIndex:indexOfCellBeingDeleted];
I think you shouldn't use cell as source for notification. Use data model instead. Also you could remove notification easily
UPDATE
Model *model = [_array objectAtIndex:indexPath.row]; model.notificationID = // here you store created notification identifier
[[UIApplication sharedApplication] scheduledLocalNotifications] // contains all local notifications, you should search you need by ID and remove it using cancelLocalNotification method.
P.S. notification ID you can store in notification userInfo
Try this
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
UILocalNotification *notif = [notificationArray objectAtIndex:indexPath];
[[UIApplication sharedApplication] cancelLocalNotification:notif];