I've setup a local notification that repeats every minute, however I need the application badge number to increment each time. When I run it at the moment it doesn't seem to increase, it just stays a 1. Please can someone help me out?
Here is how I create the notifications:
// Create the UILocalNotification
UILocalNotification *myNotification = [[UILocalNotification alloc] init];
myNotification.alertBody = #"Blah blah blah...";
myNotification.alertAction = #"Blah";
myNotification.soundName = UILocalNotificationDefaultSoundName;
myNotification.applicationIconBadgeNumber++;
myNotification.timeZone = [NSTimeZone defaultTimeZone];
myNotification.repeatInterval = NSMinuteCalendarUnit;
myNotification.fireDate = [[NSDate date] dateByAddingTimeInterval:30];
[[UIApplication sharedApplication] scheduleLocalNotification:myNotification];
After doing lot's of research I figured out the solution is that there is no solution:
iPhone: Incrementing the application badge through a local notification
It is not possible to update dynamically the badge number with local notifications while your app is in the background. You have to use push notifications.
If you use an outside service such as Parse for Push, this should be easily done. Just increment Parses badge number when a local notification is fired. Although, this is a special case.
While there's no simple applicationIconBadgeNumber++ method, as BFar mentioned, you can achieve what you're asking by updating all of the scheduled UILocalNotifications' applicationIconBadgeNumbers whenever a notification is added or removed.
While this won't work if you have notices that use repeatInterval, as long as you call scheduleNotification and decrementBadgeNumber at the right times, the class below should do the trick.
#implementation NotificationScheduler
+ (void) scheduleNotification:(NSString*)message date:(NSDate*)date {
UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
if (notification) {
notification.fireDate = date;
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = message;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = [self getExpectedApplicationIconBadgeNumber:date];
[app scheduleLocalNotification:notification];
[self updateBadgeCountsForQueuedNotifiations];
}
}
+ (void) decrementBadgeNumber:(long)amount {
[self setCurrentBadgeNumber:([self getCurrentBadgeNumber] - amount)];
[self updateBadgeCountsForQueuedNotifiations];
}
+ (long) getExpectedApplicationIconBadgeNumber:(NSDate*)notificationDate {
long number = [self getCurrentBadgeNumber];
for (UILocalNotification *notice in [self getScheduledLocalNotifications]) {
if (notice.fireDate <= notificationDate) {
number++;
}
}
return number;
}
+ (void) updateBadgeCountsForScheduledNotifiations {
long expectedBadgeNumber = [self getCurrentBadgeNumber];
NSArray *allLocalNotifications = [self getScheduledLocalNotifications];
for (UILocalNotification *notice in allLocalNotifications) {
expectedBadgeNumber++;
notice.applicationIconBadgeNumber = expectedBadgeNumber;
}
[[UIApplication sharedApplication] setScheduledLocalNotifications:allLocalNotifications];
}
+ (long) getCurrentBadgeNumber {
return [UIApplication sharedApplication].applicationIconBadgeNumber;
}
+ (void) setCurrentBadgeNumber:(long)number {
[UIApplication sharedApplication].applicationIconBadgeNumber = number;
}
+ (NSArray*) getScheduledLocalNotifications {
NSSortDescriptor * fireDateDesc = [NSSortDescriptor sortDescriptorWithKey:#"fireDate" ascending:YES];
return [[[UIApplication sharedApplication] scheduledLocalNotifications] sortedArrayUsingDescriptors:#[fireDateDesc]];
}
#end
I was able to do it using the following line while schedule the local notification
localNotification.applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber + 1;
and on the other end in the appdelegate
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
application.applicationIconBadgeNumber -= 1;
}
Try something like:
int plusOne = [myNotification.applicationIconBadgeNumber intValue];
plusOne++;
myNotification.applicationIconBadgeNumber = plusOne;
This should work.
myNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
Try this ... it worked for me in simple scenario ...
notification.applicationIconBadgeNumber = [UIApplication sharedApplication].scheduledLocalNotifications.count + 1;
And don't forget to set badge icon back to 0 when app launch.
Related
I am trying to cancel a already scheduled notification , notification is getting called but when i try to cancel a notification its not getting cancelled .
NSArray notification contains some random values when there is only one scheduled notification. can anyone help me . I am want to cancel the notification for a particular bookID.
UPDATE :
-(UILocalNotification *)scheduleNotification :(int)remedyID
{
NSString *descriptionBody;
NSInteger frequency;
UILocalNotification *notif = [[UILocalNotification alloc] init];
NSLog(#"%d",remedyID);
descriptionBody =[[self remedyDetailsForRemedyID:remedyID] objectForKey:#"RemedyTxtDic"];
frequency = [[[self remedyDetailsForRemedyID:remedyID] objectForKey:#"RemedyFrequency"]intValue];
NSArray *notificationFireDates = [self fireDatesForFrequency:frequency];
for (NSDate *fireDate in notificationFireDates)
{
notif.timeZone = [NSTimeZone defaultTimeZone];
notif.repeatInterval = NSDayCalendarUnit;
notif.alertBody = [NSString stringWithString:descriptionBody];
notif.alertAction = #"Show me";
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber = 1;
notif.fireDate = fireDate;
NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:notif.alertBody, #"kRemindMeNotificationDataKey", [NSNumber numberWithInt:remedyID],kRemindMeNotificationRemedyIDKey,
nil];
notif.userInfo = userDict;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
}
return notif;
}
- (void)cancelNotification:(int)bookID
{
int notificationBook=0;
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification *notification in notifications)
{
int notifBookId = [[notification.userInfo objectForKey:kRemindMeNotificationBookIDKey] intValue];
for (int i=0; i<[bookArray count]; i++)
{
notificationBook =[[[remedyArray objectAtIndex:i] objectForKey:#"BookID"] intValue];
}
NSLog(#"%d",[[notification.userInfo objectForKey:kRemindMeNotificationBookIDKey]intValue]);
NSLog(#"%d",notifBookId);
if (bookId == notifBookId)
{
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
NSArray notification contains some random values when there is only one scheduled notification.
It may be due to some previously scheduled notifications of that application already exists. Once try to cancel all the notifications of app starts again
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Your main problem
- (void)cancelNotification:(int)remedyId
{
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
NSLog(#"Cancelling... Before %d",[[[UIApplication sharedApplication]scheduledLocalNotifications]count]);
for (UILocalNotification *notification in notifications)
{
int notifRemedyId = [[notification.userInfo objectForKey:#"kRemindMeNotificationRemedyIDKey"]intValue]; // I change the key value
NSLog(#"remedyID : %d",remedyId);
NSLog(#"notifyId : %d",notifRemedyId);
if (remedyId == notifRemedyId) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
NSLog(#"Cancelling... After %d",[[[UIApplication sharedApplication]scheduledLocalNotifications]count]);
}
The key you have given was wrong. I think that was your problem. I figured out one more thing you are scheduling each notification twice i dont know why. Check with that.
You should move the check the inside the loop
for (int i=0; i<[bookArray count]; i++)
{
int bookId =[[[remedyArray objectAtIndex:i] objectForKey:#"BookID"] intValue];
if (bookId == notifBookId)
{
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
I want random Local Notification (Text and Sound) in every minute. I am using this below code:
self.randomIndex_text = arc4random() % [self.array_motivation count];
self.randomIndex_alarm = arc4random() % [self.array_alarm count];
NSLog(#"text %d, alarm %d",self.randomIndex_text, self.randomIndex_alarm);
This code perfectly works for
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif
{
notif.soundName = [NSString stringWithFormat:#"%#.mp3", [self.array_alarm objectAtIndex:self.randomIndex_alarm]];
[self _showAlert:[NSString stringWithFormat:#"%#",[self.array_motivation objectAtIndex:self.randomIndex_text]] withTitle:#"Daily Achiever"];
}
Display alert from above code and on Ok of alert this below method call:
-(void)insert:(NSDate *)fire
{
self.localNotification = [[UILocalNotification alloc] init];
if (self.localNotification == nil)
return;
self.randomIndex_text = arc4random() % [self.array_motivation count];
self.randomIndex_alarm = arc4random() % [self.array_alarm count];
NSLog(#"text %d, alarm %d",self.randomIndex_text, self.randomIndex_alarm);
self.localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:refTimeIntrval];
self.localNotification.timeZone = [NSTimeZone defaultTimeZone];
self.localNotification.alertBody = [NSString stringWithFormat:#"%#",[self.array_motivation objectAtIndex:self.randomIndex_text]];
self.localNotification.soundName = [NSString stringWithFormat:#"%#.mp3",[self.array_alarm objectAtIndex:self.randomIndex_alarm]];
self.localNotification.alertAction = #"View";
self.localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber]+1;
self.localNotification.repeatInterval=NSMinuteCalendarUnit;
NSLog(#"alertBody %#,soundName %#", self.localNotification.alertBody, self.localNotification.soundName);
[[UIApplication sharedApplication] scheduleLocalNotification:self.localNotification];
}
but does not work in background. I just put this above random method in
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
while ([application backgroundTimeRemaining] > 1.0)
{
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif)
{
self.randomIndex_text = arc4random() % [self.array_motivation count];
self.randomIndex_alarm = arc4random() % [self.array_alarm count];
NSLog(#"tempmethod text %d, alarm %d",self.randomIndex_text, self.randomIndex_alarm);
localNotif.fireDate = [[NSDate date] dateByAddingTimeInterval:refTimeIntrval];
localNotif.alertBody = [NSString stringWithFormat:#"%#",[self.array_motivation objectAtIndex:self.randomIndex_text]];
localNotif.soundName =[NSString stringWithFormat:#"%#.mp3",[self.array_alarm objectAtIndex:self.randomIndex_alarm]];
localNotif.alertAction = NSLocalizedString(#"Read Msg", nil);
localNotif.applicationIconBadgeNumber = 1;
[localNotif setRepeatInterval:NSMinuteCalendarUnit];
[application presentLocalNotificationNow:localNotif];
NSLog(#"sound: %#, alertAction: %#, alerBody: %#, ref: %f, str_time: %#",localNotif.soundName, localNotif.alertAction, localNotif.alertBody, refTimeIntrval, str_Time);
[self performSelector:#selector(bgmethodd) withObject:nil afterDelay:refTimeIntrval];
break;
}
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
NSLog(#"smh: %d,%d,%d",self.seconds, self.minutes, self.hours);
}
}
One more thing i noticed when i do debug that applicationDidEnterBackground call at one time only (i.e when application moves in background). After that no any method call till application open again but still i got notification text and sound continoulsy. But this text and sound is not random.
Please suggest me some idea and share your knowledge that from where this notification text and sound come when no any method call in background. And is it possible to make notification random in background.
Thanks in advance.
The first notification that you schedule when the app goes in background is repeating with interval NSMinuteCalendarUnit, and therefore the app shows only that notification every minute.
In order to get random alerts and sounds, the local notification needs to execute some code in background that will generate the next random sound and alert, which is not possible.
One way to do this is to schedule 64 (max) local notifications in advance with random sounds and alerts. When the user opens the app, you can see how many notifications were fired in background, and reschedule them.
To be sure that local notifications will be fired even if the user doesn't open the application during those 64 notifications, the last notification needs to be repeating with interval NSMinuteCalendarUnit. So after the first 63 notifications, you will lose the randomness, but if the user opens the app frequently this will not be a problem.
I have a table view as follow i did set reminders for each cell using corresponding switch on
-(IBAction)switchingbtn:(id)sender
{
UISwitch *onoff = (UISwitch *) sender;
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if(onoff.on)
{
NSLog(#"Shedule notification");
int tagValue=[sender tag];
NSMutableDictionary *dict = (NSMutableDictionary *)[alarmsArray objectAtIndex:tagValue];
NSDate *firedate = [dict objectForKey:#"date"];
NSLog(#"fire date is %#", firedate);
localNotif.fireDate = firedate;
localNotif.alertBody = #"Start Exercise";
localNotif.applicationIconBadgeNumber = 0;
// localNotif.timeZone =[NSTimeZone timeZoneForSecondsFromGMT:0];
localNotif.timeZone = [NSTimeZone systemTimeZone];
localNotif.repeatInterval = kCFCalendarUnitDay;
// [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; //**Not working**
[localNotif release];
}
No i need to cancel a preticular 1 noftication for ex 3rd swich cancels 3rd notification
else
{
// Cancel a notification not works
// [[UIApplication sharedApplication] cancelLocalNotification:localNotif];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSLog(#"cancel notification");
}
The best way to cancel single notification so far, is to create an notication that has a userInfo dictionary, in this dictionary you could add a notification ID value for an id key. You keep track of the notifications ID (storing in a plist, sql database, etc) and when you need to delete a notification you just need to ask the UIApplication instance for the scheduled notif and filter by the ID, when you find the match you just need to send the cancel method for that notification.
here is the code which you wanted
- (void)CancelExistingNotification {
//cancel alarm
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:#"notificationID"]];
if ([uid isEqualToString:[NSString stringWithFormat:#"%i",self.notificationID]])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
}
"self.notificationID" comes from a property on a custom object like alarmObject which are loaded with the help NSUserDefaults application wide.
I have this code for local notification, and I have a scheduleNotification and clearNotification using my own method. These are the codes:
- (void)clearNotification {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
- (void)scheduleNotification {
[reminderText resignFirstResponder];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Class cls = NSClassFromString(#"UILocalNotification");
if (cls != nil) {
UILocalNotification *notif = [[cls alloc] init];
notif.fireDate = [[datePicker date] dateByAddingTimeInterval:-30];
notif.timeZone = [NSTimeZone defaultTimeZone];
notif.alertBody = #"Evaluation Planner";
notif.alertAction = #"Details";
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber = 1;
NSDictionary *userDict = [NSDictionary dictionaryWithObject:reminderText.text forKey:kRemindMeNotificationDataKey];
notif.userInfo = userDict;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
[notif release];
}
}
These codes works well, but now I want to know how do I know which notification object will it delete. I would like to create an ID for a notification, meaning, one ID is equivalent to one notification. But I don't know at which part I should do that. Plus I need to find a way to include all this to be in a plist.
Hope somebody can help me. Thanks.
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification *not in notifications) {
NSString *dateString=[not.userInfo valueForKey:#"EndDate"];
if([dateString isEqualToString:#"CompareString"])
{
[[UIApplication sharedApplication] cancelLocalNotification:not];
}
}
Give user info whenever you create local notification (this is a key-value pair).
Iterate through notifications (it contains All Local Notifications) and compare value for the known key. In the above example I am using EndDate as the key and CompareString as the value.
Its Working Fine With Me.
Cheers..
(void)cancelLocalNotification:(NSString*)notificationID
{
// UILocalNotification *cancelThisNotification = nil;
// BOOL hasNotification = NO;
for (int j =0;j<[[[UIApplication sharedApplication]scheduledLocalNotifications]count]; j++)
{
UILocalNotification *someNotification = [[[UIApplication sharedApplication]scheduledLocalNotifications]objectAtIndex:j];
if([[someNotification.userInfo objectForKey:#"drdid"] isEqualToString:notificationID])
{
NSLog(#"id,notificationID(App) %# %# ",[someNotification.userInfo objectForKey:#"drdid"],notificationID);
NSLog(#"canceled notifications %#",someNotification);
[[UIApplication sharedApplication] cancelLocalNotification:someNotification];
}
}
}
I would suggest using the userInfo property on UILocalNotification, as others have mentioned. A simpler implementation that the accepted answer would be:
for(UILocalNotification* notification in [[UIApplication sharedApplication]scheduledLocalNotifications])
{
if([[notification.userInfo objectForKey:#"notification_identifier"] isEqualToString:#"notification_001"])
{
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
A for loop like this is much simpler. I'm not sure if it's more or less optimal, but it's certainly easier to read, and I assume you only have a few notifications to loop through anyway.
I am trying to use UILocalNotification in my project. I want my application to get notified every 5 seconds (non stop) in the background. I am trying the following code. It is notifying my application only for the first time after 5 seconds, after installed. I want it to be notified continuously every 5 seconds without stop. How can i achieve it?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// Initiating notification at app startup
[self InitiateLocalNotification];
return YES;
}
-(void) InitiateLocalNotification
{
NSDate *notificationDate = [NSDate dateWithTimeIntervalSinceNow:5];
UILocalNotification *notify = [ [UILocalNotification alloc] init ];
notify.fireDate = notificationDate;
//notify.applicationIconBadgeNumber = 1;
notify.soundName = UILocalNotificationDefaultSoundName;
notify.timeZone = [NSTimeZone defaultTimeZone];
//notify.alertBody = #"Local notification test";
//notify.repeatInterval = 1;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:#"notifiValue" forKey:#"notifiKey"];
notify.userInfo = infoDict;
// Schedule the notification
[[UIApplication sharedApplication] scheduleLocalNotification:notify];
[notify release];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
}
I think, you need to register for the notification again if you receive any,
your code could be :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ // Override point for customization after application launch.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// Initiating notification at app startup
[self InitiateLocalNotification];
return YES;
}
-(void) InitiateLocalNotification
{
NSDate *notificationDate = [NSDate dateWithTimeIntervalSinceNow:5];
UILocalNotification *notify = [ [UILocalNotification alloc] init ];
notify.fireDate = notificationDate;
//notify.applicationIconBadgeNumber = 1;
notify.soundName = UILocalNotificationDefaultSoundName;
notify.timeZone = [NSTimeZone defaultTimeZone];
//notify.alertBody = #"Local notification test";
//notify.repeatInterval = 1;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:#"notifiValue" forKey:#"notifiKey"]; notify.userInfo = infoDict;
// Schedule the notification
[[UIApplication sharedApplication] scheduleLocalNotification:notify];
[notify release];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// Need to register again
[self InitiateLocalNotification];
}
You are only calling
[self InitiateLocalNotification];
once, and therefore only scheduling one notification.
You must schedule each notification that you wish to receive (schedule notification 5 seconds from now, 10 seconds from now ... etc), since you don't have that kind of control over the repeat interval.
A solution would be to schedule the next one when you receive a notification, but that won't result in notifications scheduled exactly 5 seconds apart.