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.
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 got my push notification successfully in both background and foreground but my problem is when my application is in active state/foreground and push notification is arrived then i show this pushnotification message on alertview using didReceiveRemoteNotification method,
My alert view have two buttons
1) later
2) Ok.
If I press 1) "later" button then I want add this pushnotification message in notification area so after some time user can see and tap on that particular push notification and go with that and that record of push notification will remove from notification area.
This is not possible. There is no API to access notification are of iOS.
Alternative
What near alternative you can try is Local Notification. When user select later set Local Notification for that thing. You can add this Local Notification when user leave your app so that you don't get notification while user is continue with your application.
Better Approach
The most general approach for this problem is Notification screen in app. Your application has one screen which has list of received notification so that user can check that in you app. I suggest you to go with this. Because this is most common and clear idea.
You need to implement core data for Notifications but it can only happen when your Application is is Active state.
1-create a new identity everytime a new notification arrive.
2-save it.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSDictionary *Notification = userInfo;
NSString *title = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"title"];
NSString *body = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"body"];
XXNotification *objNotification = [XXNotification create];
objNotification.title = title;
objNotification.detail = body;
[XXNotification save:nil];
NSArray *arrNotification =[XXNotification allUnRead:nil];
[UtilityFunctions setApplicationBadgeNumber:[arrNotification count]];//Utility functions is my class for common functions.
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
{
[UtilityFunctions showAlertView:title message:body delegate:self cancelButtonTitle:#"Ok" otherButtonTitle:#"Cancel" withTag:99 withAccessibilityHint:[NSString stringWithFormat:#"%#:|:%#", title,body]];
}
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive || [[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.userInfo = userInfo;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = body;
localNotification.fireDate = [NSDate date];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
if (![IsLocationSaved isEqualToString:#"NO"])
{
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationForShowingNotification object: nil userInfo:nil];
}
}
}
On showing the UIAlertView, on its click event either delete that notification in DB or make a bool in it as isRead and make it YES. then save it,
On Notifications list Query the notification from DB or only those whose isRead = NO.
That is the way I did it in My Application.