Iphone Background task even after application in closed - ios

I keep reading the documentation and is just not making sense. So i decided to ask the question. Applications on the Iphone like the clock which has an alarm on it. When i set the alarm and close the application the application still notify's me at 4:30am eventhough i have closed the application. Now my understanding is that in order for something like this to work you would have to have it running on the background at all times. This is the part that does not make sense. If i completely shut down the app by double clickin my home button and then swiping up to get rid of the app, how does the app monitor time if is no longer running in the background? Apple states that their are 5 states
1-NOT RUNNING
2-Inactive
3-Active
4-Background
5-Suspended
explanation of the above are located here
i would imagine that when i shut down an application the state is not running. However the alarm application still comes on. HOW? this is killing me. Is there a special state that only native apps can have?
Any information or further understanding would be greatly appreciated.

This is not the case Miguel. What you are looking for is:
https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/Reference/Reference.html
Using UILocalNotifications, your app does not have to keep track of time at all. It schedules a notification, and the operating system keeps track of it. I have built quite a few apps with notifications/alarms. I hope this is helpful.

You can use Local notifications.
iOS will notify user when your previously added local notification fires. [iOS will add notification but your app won't be running at all. When user will tap on the notification then the app will open.]
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.repeatInterval = NSDayCalendarUnit;
[notification setAlertBody:#"Hello world"];
[notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]];
[notification setTimeZone:[NSTimeZone defaultTimeZone]];
[application setScheduledLocalNotifications:[NSArray arrayWithObject:notification]];
}
Tutorial:
http://www.appcoda.com/ios-programming-local-notification-tutorial/
http://www.icodeblog.com/2010/07/29/iphone-programming-tutorial-local-notifications/
Concept guide:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html

Related

iOS 9 cancelLocalNotification problems

I've had an app on the App Store for over a year now which uses UILocalNotifications to act as reminders. The UILocalNotifications use the repeatInterval, set to NSCalendarUnitMinute, to keep reminding the user of whatever they wanted to be reminded of.
Everything was fine with the app when building against iOS 7/8 but now that I've started to build it against iOS 9 I'm having epic issues using [[UIApplication sharedApplication] cancelLocalNotification: notification] to stop previously scheduled notifications.
I've checked the number of notifications in [[UIApplication sharedApplication] scheduledLocalNotifications] before and after cancelling a notification to verify that the count does get decremented, but when it comes round to the time that the notification would have hit its repeatInterval the notification cheerily pops up its head to haunt me...
I've tried all sorts of things... cancelling individual notifications, [[UIApplication sharedApplication] cancelAllLocalNotifications], [UIApplication sharedApplication].scheduledLocalNotifications = [NSArray array] but nothing was doing the trick at all...
A number of times I thought I'd solved the problem but then it would keep rearing its head, generally on older notifications I'd scheduled, though always seemed fine on ones I'd just recently setup.
Just now I managed to get rid of a lingering, un-cancellable notification by force quitting the app after an attempt to cancel it... which is hardly an elegant solution for end users other than myself...
Has anyone else had these kinds of issues with local notifications, possibly specifically those that are setup to auto-repeat?
For the sake of it I'll reference this similar post which could technically be called a duplicate but I'm posting this new question as the other one isn't getting any interest and needs my somewhat different situation to be described and solved! (PS if you get this question closed as a duplicate I will cry.. and no one wants to see that, right?)

iOS periodic background location updates which depends not only on significant location change

I have an app which must report user location even if it backgrounded or even killed (terminated). The issue is that the app should report the location not rare than 1 hour interval.
I'm using significant location change (SLC) to track all movements which is quite enough when user is on the go but once user stops no further updates is raised and the app has no opportunity to submit new location (while user stays in the same area but without SLC).
To cover this case I start to use Background fetches to periodically send updates location in background even without SLC). The issue here is that background fetches used to work quite often (every 20-30 min since I used then in another iOS 7.x app) but now with iOS8 / iOS9 I can get it only once a day or so which is not acceptable in my case. I have executed ton of tests, developed simple background fetch app which add a local notification on fetch. No luck to force it to work more often.
Here is my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDate *now = [NSDate date];
localNotification.fireDate = now;
localNotification.alertBody = [NSString stringWithFormat:#"Background fetch!"];
localNotification.soundName = UILocalNotificationDefaultSoundName;
NSInteger number = [UIApplication sharedApplication].applicationIconBadgeNumber;
number++;
localNotification.applicationIconBadgeNumber = number;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
completionHandler(UIBackgroundFetchResultNewData);
}
All what is done here is to add local notification on every background fetch. I always finalize the background execution with UIBackgroundFetchResultNewData.
Do you have any suggestions on how to force background fetches to work more often (or prove links that it is not possible any more)?
Any alternative solutions to meet my requirement are also welcomed!
It turned out that background fetches in iOS depend a lot on what you are doing within the handler, especially network activity. Here the list of dependencies which you should consider trying to understand if and how often iOS will execute your fetch:
time you spend in handler
result (NoData, NewData)
error handling (you will be launched less likely if you code crashes
timeouts (your code execution could be interrupted by iOS)
power usage
network activity related to result (you MUST do a network request when saying that you have NewData, otherwise your fetch could be executed next time in a day or so never.
Apps that download small amounts of content quickly, and accurately
reflect when they had content available to download, are more likely
to receive execution time in the future than apps that take a long
time to download their content or that claim content was available
but then do not download anything.
The last item turned out to be crucial in my case, because for testing purposes I declared fetches and never tried to download anything. Once I started to use network in the handler, background fetches continue to work as expected every 15-30 minutes.
Apple docs:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
I worked on a similar project. After trying various solutions, the only way I've found is the solution proposed here:
https://github.com/voyage11/Location
Here is the tutorial corresponding to the git:
http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended
All credits to https://stackoverflow.com/users/1995940/ricky
It's saved me a lot of time!

Show (local) notification when user closes app from task switcher

I'd like to show a (local) notification to the user when my app is terminated, be it by iOS itself or by the user via the task switcher.
When iOS kills the app because of memory pressure the applicationWillTerminate function is called on my AppDelegate, so I can schedule a local notification in that case.
However, when the user kills the app by swiping it to the top in the task switcher, the applicationWillTerminate function is not called (as stated in the Apple docs and various answers here on SO). And yet, there are apps that still do succeed in showing a (local) notification to the user in that case (especially fitness tracking apps, e.g. Human), asking the user to restart the app so the background tracking can continue.
I can think of some (mostly awkward, or at least battery consuming) ways to get this done, but is there a nice way to show such a notification to the user? Especially to do so almost instantly after the app is killed by the user, which excludes a lot of possible workarounds with scheduling and cancelling local notifications every n seconds in the background ...
Found it ... apparently the apps that show a notification like the one I want to show do it by using background location updates to (re)schedule a local notification so it will never show up, and once they are killed by the user the notification stays active and fires.
Doesn't sound that nice, but probably it's the only way to do it apart from pinging the app from the server periodically.
It would be nice to have a more decent (and energy-efficient) way to do this, e.g. by consistently getting the time to do something just before an app is terminated, no matter the reason for termination.
I tried like this:
Must enable background mode (bluetooth, voip, location service)
Add this code in didFinishLaunchingWithOptions:
[self addLocalNotification];
[NSTimer scheduledTimerWithTimeInterval:9.0f
target:self
selector:#selector(addLocalNotification)
userInfo:nil
repeats:YES];
in addLocalNotification
- (void) addLocalNotification{
NSDate * theDate = [[NSDate date] dateByAddingTimeInterval:10]; // set a localnotificaiton for 10 seconds
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];
// Create a new notification.
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.alertBody =#"App must run" ;
[app scheduleLocalNotification:alarm];
}}
And it works for me. addLocalNotification will run as long as app run/background. Once it is Terminated already scheduled local notification will fire on time. Time interval we can change on our interest.

(iOS) How can I speed up the reaction time of "didReceiveLocalNotification:"?

Background
I am in the early stages of learning iOS Development (and Objective C). After the latest tutorial I followed, I decided to take the lesson a little further.
After the tutorial, I had an Alarm Clock application that fired a LocalNotification at a time set by the user. Since the local notification only played the alarm sound while the app was in background mode, I didn't think it was much of an alarm clock. So I set out to add alarm functionality while the app was open and in focus.
Where I am now
My alarm clock application functions exactly as it should. If the app is open, the user receives a UIAlertView and the alarm sound.
The Problem
To trigger the UIAlertView, I am using the didReceiveLocalNotification: method.
There is a fairly big delay between the time set by the user and when didReceiveLocalNotification: is called. 38 seconds to be exact.
I may just be nitpicking, but it's killing me that I can't figure out why. I went out searching through GitHub to find some other examples, and they all seem to be following the same pattern as I am.
What might cause a delay like this? If this is normal behavior, what can be done to get rid of the delay?
Please let me know if any of my code might be helpful. As didReceiveLocalNotification: is a predefined method, and I have no control over when it is called, I'm not sure what code you might need.
Additional Information
Method for setting alarm time
- (void) scheduleLocalNotificationWithDate: (NSDate *) fireDate
{
UILocalNotification *backgroundNotification = [[UILocalNotification alloc] init];
backgroundNotification.fireDate = fireDate;
backgroundNotification.alertBody = #"Wake Up!";
backgroundNotification.soundName = #"My_Alarm.mp3";
[[UIApplication sharedApplication] scheduleLocalNotification: backgroundNotification];
}

Repeating a task when app is in background (e.g. pull something from a server), without APNs

Is there a good, Apple-approved alternative to using push notifications to trigger an app to run some code (in particular: pull new messages from a server) in a regular interval?
Disguising as VoIP app is not a good option (won't be approved, see iPhone: repeating background task)
I cannot use location updates, it should work if the user does not move around
In the simulator, using beginBackgroundTaskWithExpirationHandler with dispatch_async gives you 10 minutes of background time, and I found out that if the background "restarts itself", the backgroundTimeRemaining property always seems to be reset to 10 minutes. Here's the code.
- (void) work
{
UIApplication *application = [UIApplication sharedApplication];
NSLog(#"bg %# (T-%.1f seconds)",
[NSDate date],
[application backgroundTimeRemaining]);
sleep(10);
[application endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
[self startTask];
}
- (void)startTask
{
UIApplication *application = [UIApplication sharedApplication];
_bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"expired at %#", [NSDate date]);
[application endBackgroundTask:_bgTask];
_bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
0),
^{ [self work]; });
}
- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
/* ... */
[self startTask];
/* ... */
}
Would that be an accepted practice to run something in the background? I mean, most of the time I would just sleep(...) until I want to repeat a network request or do something useful, but the app would never really enter full background mode. Does anyone have experience with this approach? Hint: Only tested on simulator without other running apps.
The Apple-approved alternatives are listed in https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Looking at "Table 3-1 Background modes for apps", the two relevant alternatives for repeatedly getting info from a server are "Background fetch" or "remote-notification".
"remote-notification" is push notifications, which you say you don't want to use.
Therefore, "Background fetch" is the relevant choice. For example, see https://blog.newrelic.com/2016/01/13/ios9-background-execution "Downloading remote content opportunistically".
However, this does not give you (the developer) the degree of control you would have in Android. There is "setMinimumBackgroundFetchInterval", but notice that this is a MINIMUM: iOS decides when to call into your app for the next background fetch. (Apple is focused on overall battery usage and device responsiveness; once your app is in the background, design to work gracefully with however little attention it is given.)
NOTE: If the user kills your app, "Background fetch" will be killed with it. This is by design. (And is a good thing, from the user's viewpoint: most apps should stay dead if killed.)
Consider using a combination of "push notification" (remote-notification) and "Background fetch". For example, if a user permits "push notifications" by your app, then do one push daily, with a text notification to user. If they open that notification, that will open your app. Then begin the data fetching. If they hit Home button, use "Background fetch" to continue data fetching periodically through the day.
Users who are very battery-conscious may kill all their apps periodically. If they don't want to be bothered by your app today, they will ignore or delete your app's push notification. Consider this a good thing: you won't annoy users by draining battery on days that they aren't actively using your app.
Users who like to have tight control over what is running on their phone WILL NOT permit push notifications for your app. (For instance, I hate to receive daily text notifications. Don't call me, I'll call you.) In this case, once your app is killed, there is nothing that you can do (since push notification is the only way to resurrect your dead app, and I, the user, have said "No" to that). Be sure to consider how you will serve such users. (Your content may be stale when they first re-open your app.)
You can't do this on a normal iphone. And if you found out a way to do it, Apple would eventually fix the loophole and reject your app.
I don't know about jailbroken iphones, I suspect it might be possible on them somehow.
I think you can use "local notifications" to trigger something to occur at a specific time.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SchedulingandHandlingLocalNotifications.html#//apple_ref/doc/uid/TP40008194-CH5-SW1

Resources