Schedule a notification for inconsistent interval iOS - ios

I'm working on an application in which i want to show a UILocalNotification for an inconsistent interval. notification will appear on the day of week user want to see i.e. user selects monday, tuesday and friday then notification will be visible on these days of each upcoming week.
Thanks for any help in advance.

I think what you need to do is schedule multiple UILocalNotification instances for the irregular periods in your interval. You can use the repeatInterval property to have each UILocalNotification repeat.
For your example, you could have three UILocalNotification instances scheduled for Monday, Tuesday, and Friday, and then set the repeatInterval value of each of these instances to NSWeekCalendarUnit.

A UILocalNotification takes an NSDate for its fireDate property. Why don't you create an NSDate instance based on feedback from the user through the UI and use that?
To create the NSDate object, you could either simply call initWithTimeIntervalsSinceNow: using a multiple of seconds. For example, to create an NSDate representing the time 6 days and 5 hours from now:
NSDate* futureDate = [[NSDate alloc] initWithTimeIntervalSinceNow:6*24*60 + 5*60];
Or, if you need to take the user's particular calendar (remember there are many different calendars in use around the world) or timezone into account, you should also check out the NSCalendar and NSTimeZone classes. The 'Date and Time Programming Guide' is a great walkthrough of these.

Put On AppDelegate.m and call from enterbackground and terminal method
-(void)localNotification{
UILocalNotification *scheduledAlert;
[[UIApplication sharedApplication] cancelAllLocalNotifications];
scheduledAlert = [[[UILocalNotification alloc] init] autorelease];
NSDate *date = [NSDate date];
NSLog(#"%#",date);
scheduledAlert.fireDate = [NSDate dateWithTimeIntervalSinceNow:86400];
scheduledAlert.timeZone = [NSTimeZone defaultTimeZone];
scheduledAlert.repeatInterval = NSDayCalendarUnit;
NSArray *arr =[[NSArray alloc]initWithObjects:#"Your Notification 1",#"Your Notification 2",#"Your Notification 3",nil];
int jk = arc4random()%arr.count;
scheduledAlert.alertBody = [arr objectAtIndex:jk];
[[UIApplication sharedApplication] scheduleLocalNotification:scheduledAlert];
}

Related

Trigger local notifications automatically daily on dynamic time given in arrays Objective c ios

I have an array of hours hoursArray and array of minutes minutesArray and I am getting the current date from the system now I have the arrays who have the elements of the current month it means if there are 30 days in April there will be 30 hours/minutes in hoursArray/minutesArray which I have inserted in the arrays, and I am getting current date as an index of arrays.
What I have done is that notifications triggers in current day but it does not trigger the next day until I use app daily because when I use app daily before the trigger time method will be called when I turn to background mode and notification rings.
Now I want the notifications should be triggered automatically when date changes, even when I don't use the application for somedays, these all stuff should be in didEnterBackground... method of appDelegate
I have followed this answer, but it is used for same time daily But I want different time daily from arrays based on Current date's index of arrays (it means the current day e.g today is 19 April the index of hours and minutes array should be 19).
Here is how my arrays look like
Hour array = [9, 10, 11, 13, 14, 11, 17, 2, 15, 5.... and so on]
Minute array = [23, 00, 04, 58, 59, 12, 01, 33,.... and so on]
method call in appdelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.viewController triggerAutomaticallyDaily];
[self applicationSignificantTimeChange:application];
[self refreshAlarm];
}
method inside viewcontroller.m
-(void)triggerAutomaticallyDaily {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
NSDate *now = [NSDate date];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:now];
[components setHour:hoursArray[currentDay]]; //currentDay the todays date is 16 I am getting current date from system.
[components setMinute:minutesArray[currentDay]];
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.fireDate = [calendar dateFromComponents:components];
notification.repeatInterval = NSDayCalendarUnit;
[notification setAlertBody:#"This is your task time"];
// notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
Significant time changes after each midnight, method in Appdelegate
-(void)applicationSignificantTimeChange:(UIApplication *)application {
[self.viewController triggerAutomaticallyDaily];
}
Refresh Alarm method in Appdelegate
- (void)refreshLabel
{
//refresh the alarm on the main thread
dispatch_async(dispatch_get_main_queue(),^{
[self.viewController triggerAutomaticallyDaily];
});
// check every 10000s
[self performSelector:#selector(refreshLabel) withObject:nil afterDelay:10000];
}
Have a look at didEnterBackground... when I quit my app the notication method will be called just once. isn't is?? and how the daily notification can I receive when I don't even open the app for a week but I want to get notifications, How method will be called? is method called every time in background mode?
Is there any way so I can schedule the notification and and when the first notification done the second should be triggered and if second done then third should be triggered and so on in the background mode even I don't open the app for a week?? the notifications should be triggered based on current date and time given in arrays.
UPDATE
I have even placed the refresh function which refreshes the trigger after each and every 10000 seconds but it is not working.
I have also added significantTimechanges , if there is midnight changes but its not working to here is how I have defined that all.
Important Note: Developer can not do anything if application is in kill state or in background for a long time. So this can not be done.
There are many questions for your requirement:
1.1: How many days data you have in one service, for a month, for a year or ?
1.2: Why not push?
1.3: Why do you want to schedule local notification on daily basis while you can schedule many at once?
1.4: There is no way to make changes in the app when its not opened (killed by user) so you can not do anything in that case.
Now come to what we can do:
2.1: Considering you are getting monthly data. So you should schedule all the local notifications at once in for loop by increasing the day component and setting the corresponding time (from your arrays by day index). And its your luck if user opens the application once in a month (90% chances he will) then you can request to server for next month data and do the same.
2.2: Why not this is being handled at server end and use push notifications instead of local. Server guys can configure a cron job for every minute which will fetch the all hours and minutes for users and will send the push.
My suggestion not to go with local but all maximum you can go with 2.1 (schedule all month notifications at once).
Just use below statement instead of NSCalendar
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.fireDate = [[NSDate date] dateByAddingTimeInterval:(hours*3600)+(Mins*60)];
//Unit of time interval should be in Second
notification.repeatInterval = NSDayCalendarUnit;
[notification setAlertBody:#"This is your task time"];
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
As others have said, the better technique is to schedule all of the notifications at once. This is what I do. However, there is a system limit of 64 pending local notifications. In your case, the scheduled notification should trigger every day for 64 days. I have a more difficult problem because I need to schedule notifications every 15 minutes. So, if my users don't respond within 16 hours, they will not get further notifications (64/4 = 16). Also, note that UILocalNotification is deprecated, so you should use UNNotificationRequest. Note that the identifier in UNCalendarNotificationTrigger must be unique for each request.
content.categoryIdentifier = #"com.nelsoncapes.localNotification";
NSDate *today = [NSDate date];
NSDate *fireDate = [today dateByAddingTimeInterval:interval];
// first extract the various components of the date
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger year = [calendar component:NSCalendarUnitYear fromDate:fireDate];
NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:fireDate];
NSInteger day = [calendar component:NSCalendarUnitDay fromDate:fireDate];
NSInteger hour = [calendar component:NSCalendarUnitHour fromDate:fireDate];
NSInteger minute = [calendar component:NSCalendarUnitMinute fromDate:fireDate];
NSDateComponents *components = [[NSDateComponents alloc]init];
components.year = year;
components.month = month;
components.day = day;
components.hour = hour;
components.minute = minute;
…
// construct a calendarnotification trigger and add it to the system
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier: identifier content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *error){
if(error){
NSLog(#"error on trigger notification %#", error);
}
}];

Trigger local notification set from scheduleLocalNotification

In our app, if a user has set a reminder from us for the future, we set a local notification via,
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil) return;
NSDate *fireTime = [[NSDate date] addTimeInterval: 60 * 60]; // adds 1 hour (60 seconds * 60 minutes)
localNotif.fireDate = fireTime;
localNotif.alertBody = #"Alert!";
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
Obviously this is easy to test if it's just a few seconds / minutes, but to test 100% when it's scheduled for far in the future, for us to test that, is our only option to just wait?
On Android, you're able to simply adjust the date and time of the phone, and that triggers the local notification, but thus far, I can't see any way to do it on iOS.
Is there a way to?
You need to set the timeZone property of the UILocalNotification. Otherwise, the notification is simply a countdown timer.
localNotif.timeZone = [NSTimeZone systemTimeZone];

Update icon badge daily at midnight

I am making an app which shows the number of days since two people are in a relationship. I would like to show the number of days on the app icon badge. I know how to do this once the user leaves the app, however I want to update the icon badge everyday even if the app isn't opened or running in the background so the user knows the number of days without having to even open the app. "BeenTogether" is a similar app and is doing the same so I am sure it is possible somehow. Any thoughts on how could I accomplish this?
I'm sure that variations of this have been asked about a zillion times, but the answer is still no. There are ways you can approximate it, but all have downsides.
Silent push notification. Of course this means you need to know their time zone and they need to have a network connection.
Background fetch. This operates "periodically" so you couldn't update the badge at exactly midnight but it would often be pretty close.
You can achieve same thing with help of Local Notification. I assume that you're having date when they started date. So, you can update badge count everyday with Local Notification.
I am not sure everyone understood my question right, because it turns out to be possible to increment the icon badge by one everyday at midnight, without having to schedule 64 notifications. The solution is rather simple:
//Set a random date (only the time matters because it is repeated everyday), but make sure that the time is at midnight!!
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear:2015];
[dateComponents setMonth:1];
[dateComponents setDay:1];
[dateComponents setHour:0];
[dateComponents setMinute:0];
//Create an NSDate from the date components
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDate *configuredDate = [calendar dateFromComponents:dateComponents];
//Schedule a local notification, set the repeatInterval to daily
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = configuredDate;
localNotification.alertBody = nil;
localNotification.alertAction = nil;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.repeatInterval = NSCalendarUnitDay;
//Add one to the icon badge number
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

iOS local notification custom data

I'm displaying a local notification every day at 9AM with exchange rates. But if value of (let's say euro for example) is the same as yesterday then it should't fire. I'm downloading data from my server using XML. So my question is it possible to parse XML data(every day at 9AM before displaying notification) while app is not running (killed with task manager), since displaying notifications is (even when app is killed totally).
This is how I fire my notification:
NSDate *now = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:now];
[components setHour:9];
// Gives us today's date but at 9am
NSDate *next9am = [calendar dateFromComponents:components];
if ([next9am timeIntervalSinceNow] < 0) {
// If today's 9am already occurred, add 24hours to get to tomorrow's
next9am = [next9am dateByAddingTimeInterval:60*60*24];
}
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = next9am;
notification.alertBody = #"Euro value: <PARSED VALUE HERE>";
// Set a repeat interval to daily
notification.repeatInterval = NSDayCalendarUnit;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
If you can send APNS push notifications to your app you can wake it from background and have it process your xml (when exchange rates change for example) and schedule the local notification.
You have to use the silent push notification. It will launch you application in background without knowing the user and then you can download the xml and do the comparison. if it is same fire the local notification which will shown to the user and then user can proceed further.
NOTE: Apple gives max 30 seconds to perform you task in background

NSDate and TimeZone Issues

I am trying to get my app to fire a notification based off a scheduled event. The date given is from a schedule that will take place in EST. The time given is Fri Feb 21 2014 12:00:00 -0500 (Noon EST).
When the button to schedule a notification is pressed, it runs this code:
NSString *message = [#"15 minutes until " stringByAppendingString:self.thetitle];
NSLog(#"original%#", self.thedate);
NSDate *newDate = [self.thedate dateByAddingTimeInterval:-60*15];
NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
// [formatter3 setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
[formatter3 setTimeStyle:NSDateFormatterShortStyle];
[formatter3 setDateStyle:NSDateFormatterShortStyle];
NSString *detailstext = [formatter3 stringFromDate:newDate];
NSDate *othernewdate = [formatter3 dateFromString:detailstext];
NSLog(#"other%#", othernewdate);
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.timeZone = [NSTimeZone systemTimeZone];
notification.fireDate = othernewdate;
notification.alertBody = message;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.hasAction = YES;
notification.alertAction = NSLocalizedString(#"View", #"View notification button");
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
Since the time being set on the notification fireDate is the othernewdate, I ran an NSLog in the console to see what it showed. It came back:
2014-02-21 16:45:00 +0000
This seems to be perfect, because that time in EST would be 11:45 AM, or 15 minutes before noon, which is what I wanted.
The issue is this:
I am testing this in CST. I run the app, tell it to schedule a notification for this event, and then change my phone clock to be EST and it ends up firing the notification at 10:45.
There will be people using this app from different time zones, and then traveling to EST for when the conference that this app is for starts. I don't want them to schedule lots of notifications while in a different time zone and have it fire at the wrong time. Any suggestions?
If you want the notification to fire at an absolute date/time, independent of the time zone, then you must set notification.timezone = nil.
From the documentation:
"The date specified in fireDate is interpreted according to the value of this property. If you specify nil (the default), the fire date is interpreted as an absolute GMT time, which is suitable for cases such as countdown timers. If you assign a valid NSTimeZone object to this property, the fire date is interpreted as a wall-clock time that is automatically adjusted when there are changes in time zones; an example suitable for this case is an an alarm clock."

Resources