iOS local notification custom data - ios

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

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);
}
}];

Scheduled local notifications are irregular

I'm having significant trouble with my iOS local notifications. I have an app, written in Objective-C, that allows the user to pick the time the notification fires, as well as the days of the week (it should fire every week on the specified days at the specified time). I have no trouble with the time of day the notification fires, that works correctly. However, when I specify the day(s) it should fire, odd things happen. At first, they fire once, but every day rather than only the specified days. Then, after the first week, they fire every day, but not only once. Instead, they fire as many times as days are specified (so if Sunday, Monday and Tuesday are chosen, each day, the user will receive 3 consecutive notifications at the specified time).
This is the code I'm using to set up the notifications.
When the "Save" button is tapped, the first thing that happens is a clearing of all notifications, to make way for the new ones.
//cancels all notifications upon save
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Next, I use NSDate, NSCalendar and NSCalendarComponents to get the specifics for the current time, as well as the components from my UIPicker (which is used to select the time of day)
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:now];//get the required calendar units
Then, I get the units for the time from the UIPicker, and the actual time, also from the picker.
NSDateComponents *pickedComponents = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:picker.date];
NSDate *minuteHour = [calendar dateFromComponents:pickedComponents];
[[NSUserDefaults standardUserDefaults] setObject:minuteHour forKey:#"FireTime"];
After that, I set the text I want to show up in the notification
NSString *reminder = #"Reminder text!";
Next is the actual setup of the notification. They're all the same (with the day of the week changed, of course), so I'll just show the one for Sunday.
//sunday
UILocalNotification *localNotificationSunday = [[UILocalNotification alloc] init];
if ([sundayTempStatus isEqual:#"1"])
{
//permanently save the status
[[NSUserDefaults standardUserDefaults] setObject:#"1" forKey:#"Sunday"];
//set up notifications
//if it is past sunday, push next week
if (components.weekday > 1)
{
components.day = components.day + 7; //if already passed sunday, make it next sunday
}
//components.day = 1;
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDate *fireDate = [calendar dateFromComponents:components];
localNotificationSunday.fireDate = fireDate;
localNotificationSunday.alertBody = reminder;
localNotificationSunday.timeZone = [NSTimeZone systemTimeZone];
localNotificationSunday.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotificationSunday];
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:#"0" forKey:#"Sunday"];
}
Any help is greatly appreciated, and if any additional info or code is needed, I'll gladly provide it.
When code becomes repetitive, it often becomes more error-prone. I've written out a simple method that should take care of the scheduling of the reminders.
- (void)scheduleNotificationForDayOfWeek:(int)dayOfWeek withPickedComponents:(NSDateComponents *)pickedComponents andReminderString:(NSString *)reminderString {
NSCalendar *calendar = [NSCalendar currentCalendar];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[NSDate date]];
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDateComponents *additionalComponents = [[NSDateComponents alloc] init]; // to be added onto our date
if ([components weekday] < dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday]); // add the number of days until the next occurance of this weekday
} else if ([components weekday] > dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday] + 7); // add the number of days until the next occurance of this weekday
}
NSDate *fireDate = [calendar dateFromComponents:components];
fireDate = [calendar dateByAddingComponents:additionalComponents toDate:fireDate options:0]; // add on our days
notification.fireDate = fireDate;
notification.alertBody = reminderString;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
What this does is actually pretty simple. Call it with a day of the week (e.g., 0 = Sunday, 1 = Monday), and it will schedule a repeating reminder for that day. I couldn't reproduce your issues in my tests with your Sunday code, so I figured that somewhere among repeating that code you must have made an error.
In this method, the fire date getting has been simplified. It uses NSDateComponents to easily get the next occurrence of that weekday. Call it like this: [self scheduleNotificationForDayOfWeek:0 withPickedComponents:pickedComponents andReminderString:#"Hello, world!"]; (which would show "Hello, world!" every Sunday at the specified components)
With this snippet, you should be able to get rid of most of the repeated statements in your code, and simplify how setting notifications is done. For me, this worked perfectly.

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];

Schedule a notification for inconsistent interval 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];
}

Resources