Objective-C local notifications firing two times - ios

I'm using - (void)applicationDidEnterBackground:(UIApplication *)application in my AppDelegate.m file and I'm displaying a notification everyday like this:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
UIApplication *myapp = [UIApplication sharedApplication];
if (hour > 8 && hour < 10)
{
notification.fireDate = [components date];
notification.repeatInterval = 0;
notification.soundName = #"";
notification.alertBody = #"This is an notification!";
[myapp scheduleLocalNotification:notification];
}
}
Everything works fine except when notification is fired and app closed after user opens an app and than close it notification will fire again. Is there some method different than - (void)applicationDidEnterBackground:(UIApplication *)application(alert must show even when app is closed completely [killed with task manager]) or I need to solve it with some code.
Thanks!

When your app has been closed completely there is nothing more you can do. The method you're using is correct for when the app enters the background. applicationWillTerminate is called just before the app is terminated. After that point, that's it. No more.

Related

How to generate faster local notification in iOS?

I am generating Local notification when Push notification(Actionable) are received but app is closed or in background. I have used following code to generate local notification in objective-c.
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
// localNotification.fireDate = [NSDate date];
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.alertBody = #"Security settings enabled, tap to start the application";
localNotification.category = #"LOCAL_NOTIFICATION"; // Same as category identifier
// [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
1.When i drag notification trey down(Notification Center) not from alert it generate local notification fine in 1 sec.
2.But while press action from alert(while at home) it
it takes 3-4 seconds for local notification to appear.
Why there is time difference between action from alert(press action from home) and Notification center(swipe down notification trey)
generating local notification?
How to make it faster? Thanks in advance.
Try to use the presentLocalNotificationNow method instead of scheduleLocalNotification to make your notification fire instantly:
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];

Is it possible to trigger a local notification after an event IOS?

Im working on an app that does some computationally heavy tasks that take a long time. I want to notify the user with a local push notification when the task is done. Is this possible? The only information I have been able to find online is to do with triggering notifications at certain times/dates or if the app has entered the background or terminated, all of which is done in the appDelegate. Is there a way to do this in my own classes?
Thanks.
I'm not 100% certain you're looking for a UILocalNotification example because the post title mentions push notifications. Either way, you can schedule local notifications from any class you want
- (void)throwLocalNotificationWithMessage:(NSString*)message {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDate *now = [NSDate date];
localNotification.fireDate = now;
localNotification.alertBody = message;
localNotification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[UIApplication sharedApplication].applicationIconBadgeNumber++;
}
Also, for my needs I throw these local notifications when region monitoring detects boundary enter/exit changes. This code runs while my app is in the background, as well, and in that case they appear like push notifications.
The above answer by Aaron works fine but don't forget to ask permission for Local Notification. In my case case I ask permission at AppDelegate under -
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and here is the code for iOS8 and iOS9
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}

UILocalNotification fired but not showing, or showing but not visible in notification center, or firing like a charm

I've been struggling for the past few days on the local notifications on my app.
Basically the goal is to pop a notification when the user approches an address.
here is the code:
NSMutableArray *notifications = [#[] mutableCopy];
for (CCAddress *address in results) {
CCCategory *category = [address.categories.allObjects firstObject];
NSDictionary *userInfo = #{#"addressId" : address.identifier};
UILocalNotification *localNotification = [UILocalNotification new];
if (category == nil)
localNotification.alertBody = [NSString stringWithFormat:#"Vous ĂȘtes proche de %#", address.name];
else
localNotification.alertBody = [NSString stringWithFormat:#"Vous ĂȘtes proche de %#, %#", address.name, category.name];
localNotification.alertAction = #"Linotte";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = userInfo;
[notifications addObject:localNotification];
address.lastnotif = [NSDate date];
}
[managedObjectContext saveToPersistentStore:NULL];
[UIApplication sharedApplication].scheduledLocalNotifications = notifications;
The result is actually totally random, but there is something I know for sure: the geofencing works well, as you can see I set the date of the notification in lastNotif, so I know when they are fired.
Sometimes I see the notification pop, but doesn't stay in the notification center, but most times nothing happens, even if I see by the date that It actually fired, and sometimes everything goes fine.
I tried many things, like using presentLocalNotificationNow, setting a fireDate with a 1 second delay between each, and other things I don't even remember...
So, obviously there is something I missed in the documentation, but what ?
thanks.
PS: the app is in background or off when it happens, I'm aware of didReceiveLocalNotification.
PS2: I actually don't know if those that I don't see at all actually fired, because they don't show up in the notification center, so maybe they fired but I have absolutely no way to see them if I don't have my phone's screen in sight when they do.
EDIT: So, I've been doing some tests around my house, phone closed, screen locked. The real syndrom is that when a notification pops, it only turns the screen on, and the phone vibrates (I was sound off), then nothing...
I don't see that you're setting a fireDate. I can't recall what that defaults to.
Ok, so as intended, it was kind of stupid.
Before the code I posted I had:
if ([results count] == 0) {
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
return;
}
But, when you set applicationIconBadgeNumber to 0, it removes all notifications from notification center !
The documentation says nothing about this (https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html).
You need to add registerUserNotificationSettings in didFinishLaunchingWithOptions it give us notification Alert
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification) {
application.applicationIconBadgeNumber = 0;
}
return YES;
}

Perform Action At DatePicker Time

I need to send a text message when the current time equals the time selected in the UIDatePicker. How might I do this? You don't need to include the code to send the message, I already have that coded. I've tried all sorts of things with NSTimer and if - then statements but none have worked.
Edit: Since I wrote this question I've found a better way to do things. I just need to set a local notification and when received execute my code with -(void)didRevieveLocalNotification. Here is what I have so that any googlers can hopefully be helped.
NSDate *pickerDate = [self.datePicker date];
//Set Local Notification
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.fireDate = pickerDate;
notif.timeZone = [NSTimeZone defaultTimeZone];
//----------------------------------------------------------------------
notif.alertBody = #"Tap to send your text message!";
notif.alertAction = #"send message...";
notif.soundName = #"sms_alert_nova.caf";
notif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
well i would use a local notification... something like this
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = theDate //The date that your picker has selected
notification.alertBody = #"Hey, the time just expired!"
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
Then in your AppDelegate
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
//Code to manage the notification logic
}
Hope this helps, the user will get the alert even if on background.. if on background the user must click the alert to let your application know that the local notification triggered, if he does (or he is on your app already, then the app delegate method will trigger letting your app know that the notification fired...
Hope this helps!

detect unacknowledged UILocalNotifications

It seems that
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and
didReceiveLocalNotification:(UILocalNotification *)notification
are only triggered if the user acknowledges the UILocalNotification, for example by swiping the slider or touching the entry in iOS's Notification pull-down.
Is there any way to tell that a UILocalNotification has gone off if the user ignores the UILocalNotification and re-enters the app by simply clicking on the app icon?
I should mention that this really only applies to repeating notifications because the firing of non-repeating notifications can be detected by observing the total count. That is, when they fire, the vanish from [[UIApplication sharedApplication] scheduledLocalNotifications].
I'm looking for something like..
[[UIApplication sharedApplication] unacknowledgedLocalNotifications]
Alas, I can't find anything like it.
Well, you can check your scheduled notifications inside [[UIApplication sharedApplication] scheduledLocalNotifications]. To find out if a scheduled repeating notification has fired access the fireDate property to see what was the initial date set for the notification. Then check the repeatInterval property.
So there you have 2 variables, one is the initial NSDate, lets say 2013-05-08 12:00 and second is the repeat interval, lets say daily. And by doing a [NSDate date] you will get the current date which where I'm located (in Sweden) is now 2013-05-09 22:45. So this means that there is one notification the user has not acted on.
So you will need to create a method that will take these arguments and then iterate from the initial date to see how many notifications that have been missed until the current datetime.
You will find NSCalendars dateByAddingComponents:toDate:options useful.
Everyone has likely since moved on, but I'd like to share my solution to this problem. (Sorry about the long variables names...)
The idea is simple: always keep the fireDate in the future.
-every time didFinishLaunchingWithOptions or didReceiveLocalNotification is invoked, simply cancel your current notification and reschedule a new one with a fireDate one interval unit in the future
-When your app launches iterate through all scheduled notifications, if the fireDate is not in the future you know that it was ignored
In my case, the notifications have a weekly repeat interval. I first reschedule any acknowledged notifications in didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification* localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif != nil)
{
[NotificationsHelper rescheduleNotification:localNotif];
}
}
And also in didReceiveLocalNotification:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *) notification
{
[NotificationsHelper rescheduleNotification:notification];
}
At App Launch I check all notifications for any with a fireDate in the past:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self checkLocalNotifications:application];
}
Code for my "checkLocalNotifications" function:
- (void) checkLocalNotifications:(UIApplication *) application
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* eventArray = [app scheduledLocalNotifications];
for (int i = 0; i < [eventArray count]; i++)
{
UILocalNotification* notification = [eventArray objectAtIndex:i];
if ([NotificationsHelper wasWeeklyRepeatingNotificationIgnored:notification])
{
[NotificationsHelper rescheduleNotification:notification];
NSLog(#"NotificationWasIgnored: %# %#",notification.alertAction, notification.alertBody );
}
}
}
Code for my "wasWeeklyRepeatingNotificationIgnored" function:
+ (BOOL) wasWeeklyRepeatingNotificationIgnored:(UILocalNotification*) the_notification
{
BOOL result;
NSDate* now = [NSDate date];
// FireDate is earlier than now
if ([the_notification.fireDate compare:now] == NSOrderedAscending)
{
result = TRUE;
}
else
{
result = FALSE;
}
return result;
}
Code for my "rescheduleNotification" function:
+ (void) rescheduleNotification:(UILocalNotification*) the_notification
{
UILocalNotification* new_notification = [[UILocalNotification alloc] init];
NSMutableDictionary* userinfo = [[NSMutableDictionary alloc] init];
[new_notification setUserInfo:userinfo];
[new_notification setRepeatInterval:the_notification.repeatInterval];
[new_notification setSoundName:UILocalNotificationDefaultSoundName];
[new_notification setTimeZone:[NSTimeZone defaultTimeZone]];
[new_notification setAlertAction:the_notification.alertAction];
[new_notification setAlertBody:the_notification.alertBody];
[new_notification setRepeatCalendar:[NSCalendar currentCalendar]];
[new_notification setApplicationIconBadgeNumber:the_notification.applicationIconBadgeNumber];
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:the_notification.fireDate];
NSInteger weekday = [weekdayComponents weekday];
NSDate* next_week = [self addDay:weekday toHourMinute:the_notification.fireDate];
[new_notification setFireDate:next_week];
[[UIApplication sharedApplication] scheduleLocalNotification:new_notification];
[[UIApplication sharedApplication] cancelLocalNotification:the_notification];
}
If your UILocalNotifications increment the application icon badge number (i.e. the number in the red circle on the top right of the app's icon), then there is a ridiculously simple way to check for unacknowledged UILocalNotifications: just check what the current applicationIconBadgeNumber is:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
int unacknowledgedNotifs = application.applicationIconBadgeNumber;
NSLog(#"I got %d unacknowledged notifications", unacknowledgedNotifs);
//do something about it...
//You might want to reset the count afterwards:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

Resources