When I Open my app & do some stuff (Say navigate to certain
ViewController), then I don't Touch the App for few minutes iPhone gets locked(App Goes in BackGround State).
Now After few
minutes (about 5 minutes) When I Unlock the iPhone My App get Killed.It
is not there in Opened State(Active State). I need to open it explicitly by clicking App Icon.
I am not doing anything in BackGround State
One more thing to add is App is not Crashing
If you checked correctly that your app does not crash, it shows in the multitasking UI and you're not executing code in the background, then I would say that your app is being terminated by the system (due to memory pressure or something else).
Apple's documentation mentions:
Apps must be prepared for termination to happen at any time and should
not wait to save user data or perform other critical tasks.
System-initiated termination is a normal part of an app’s life cycle.
The system usually terminates apps so that it can reclaim memory and
make room for other apps being launched by the user, but the system
may also terminate apps that are misbehaving or not responding to
events in a timely manner.
Suspended apps receive no notification when they are terminated; the
system kills the process and reclaims the corresponding memory. If an
app is currently running in the background and not suspended, the
system calls the applicationWillTerminate: of its app delegate prior
to termination.
So what happened in your scenario is that the app entered the suspended state and after a period of time (those 5 minutes that you mention) the app was terminated by the system.
Take a look at the Background Transition Cycle.
If you want to reduce the possibility that your app will get terminated due to memory pressure, then take a look at What to Do When Your App Enters the Background, specifically:
Free up memory as needed. Release any cached data that you do not need
and do any simple cleanup that might reduce your app’s memory
footprint. Apps with large memory footprints are the first to be
terminated by the system, so release image resources, data caches, and
any other objects that you no longer need. For more information, see
Reduce Your Memory Footprint.
Make sure background modes are on from capabilities options (i have worked on a navigation app and keep app alive in background for more than 8 hours for tracking)
in objective C implement following code
- (void)backgroundCleanDisk {
Class UIApplicationClass = NSClassFromString(#"UIApplication");
if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:#selector(sharedApplication)]) {
return;
}
UIApplication *application = [UIApplication performSelector:#selector(sharedApplication)];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
[self cleanDiskWithCompletionBlock:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}
Related
I use this code to execute function every X minutes:
- (void)executeEveryOneMinute
{
[self myFunction];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self executeEveryOneMinute];
});
}
And it works when app is in foreground.
But when app goes background it doesn't work anymore.
When I return app to foreground again it execute function once.
And continue to call function every minute again.
So how to make this to work in background too?
See the Background Execution and Multitasking section of the iOS App Programming Guide: App States and Multitasking for a discussion of the possibilities. You can, for example, keep the app running in the background for a few minutes in order to complete some finite length task. Or you can continue to run the app in the background for a longer period of time if it's performing one of a very particular list of functions (quoting from the aforementioned document):
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background.
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
Apps that implement these services must declare the services they support and use system frameworks to implement the relevant aspects of those services. Declaring the services lets the system know which services you use, but in some cases it is the system frameworks that actually prevent your application from being suspended.
But, a fundamental design principle in iOS battery/power management is that random apps can not (and should not) continue to run in the background. If you share what precisely you're trying to do (namely, what precisely you're doing inside that executeEveryOneMinute method), though, we can offer counsel on how to achieve the desired effect, if possible.
If you're trying to have an upload continue in the background, in iOS 7 and greater, you should consider using NSURLSession with a background session configuration ([NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; there is a similar method in iOS 8). This will continue to attempt to upload (automatically, without further intervention on your part) not only after your app has left the foreground, but even after the app is terminated (e.g. due to memory pressure or a crash). AFNetworking offers a NSURLSession-based class, AFURLSessionManager, which supports this (though it's not NSOperation-based). This way, you enjoy background uploads, but conforms to Apple guidelines on background operation, notably with less dramatic battery impact than retrying yourself every 60 seconds.
I'd suggest you refer to the latter part of WWDC 2013 video What’s New in Foundation Networking, which demonstrates this process (they're doing a download, but the idea is the same for uploads).
Timer works on Main thread. When application goes into background, its timers become invalid. So, you cant do the same when application goes into background.
You can't do this with help of timer as it will be invalidated in background. You can try check this.
You should use background tasks to achieve what you want
UIApplication* app = [UIApplication sharedApplication];
task = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
NSLog(#"Started background task timeremaining = %f", [app backgroundTimeRemaining]);
if (connectedToNetwork) {
// do work son...
}
[app endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
});
plz help me out how much time UIApplication is going to run in the background state.like when we press home button etc
Limitation is as following:
10 mins for iOS6
3 mins for iOS7
Just in your app delegate implement:
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}
After 600s (iOS6) or 180 s (iOS7) the expiration handler is called - you have to finish immediately - no chance for any time consuming task or app will crash.
I suggest you to take a look at Background Execution and Multitasking, briefly:
Most apps are moved to the suspended state shortly after entering the
background. Only apps that provide important services to the user are
allowed to continue running for any amount of time
It runs something like 5 seconds.
You can also do a special process to ask more time to end a long task (like upload etc..).
Everything is explained here : https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
Have a nice reading session :)
The app is in the background and executing code. Most apps enter this state briefly on their way to being suspended. However, an app that requests extra execution time may remain in this state for a period of time. In addition, an app being launched directly into the background enters this state instead of the inactive state. For information about how to execute code while in the background, see “Background Execution and Multitasking.”
Edited:
Support for some types of background execution must be declared in advance by the app that uses them. In Xcode 5 and later, you declare the background modes your app supports from the Capabilities tab of your project settings. Enabling the Background Modes option adds the UIBackgroundModes key to your app’s Info.plist file. Selecting one or more checkboxes adds the corresponding background mode values to that key. Table 3-4 lists the background modes you can specify and the values that Xcode assigns to the UIBackgroundModes key in your app’s Info.plist file.
I have a voip app and it needs to run in the background. To my understanding these are the things I need to do:
Flag the app as voip.
Set the 'application does not run in background' flag to NO.
Set an expiration handler, a piece of code that extends the standard 10 minutes of execution time you get.
More?
I set both flags in the info.plist file and I get my 10 minutes. I tried what is suggested in this post. Here is my code:
//in didFinishLaunchingWithOptions:
expirationHandler = ^{
NSLog(#"ending background task");
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
NSLog(#"restarting background task");
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
NSLog(#"finished running background task");
};
//in applicationDidEnterBackground
NSLog(#"entering background mode");
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// inform others to stop tasks, if you like
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyApplicationEntersBackground" object:self];
//this while loop is just here for testing
inBackground = true;
while (inBackground) {
NSLog(#"stayin alive!!"); //this keeps going forever
sleep(10);
}
});
The situation:
I use a third party library that handles the communication with our webservice. The service is a CommuniGate pro server. I receive presence updates (online/offline) and instant messages from contacts via the library. The library is CommuniGate's ximss library, a protocol they made which is similar to xmpp and is used for xml-based sip requests, as well as IM and presence. When the user logs in to the app, he sees his contacts (CmmuniGate friends list) and he can choose to call one. After a ximss verification message has been sent and the other side accepted the call it logs the start time of the call and starts a facetime call.
The problem:
When the app enters the background by pressing the home button, I start seeing the 'stayin alive' message in the log and every ten minutes I see that it restarts the background task.
When the app enters the background by pressing the power button, the 'staying alive' messages start showing up for ten minutes, after that it restarts the background task and start restarting it about every 50-100 miliseconds.
I would've been fine with this for now, even it eats battery, because I have time to work on updates and our users don't own the ipads, we do. The problem for me now is that the ximss library loses it's connection (it is session-based). I could restart the session in the library, but this means quite a bit of data transfer to fetch the contacts list and some users use 3g.
I can't edit the library's source, nor can I see it, so I don't know if it creates the sockets the right way.
What do I have to do to handle both situations correctly? I don't even understand why there is a difference.
You cannot re-extend background tasks like this; your app is likely to be terminated. If this is working, it's because you have the background voip mode enabled, not because you are restarting the background task.
Once you have set the voip plist entry, iOS will attempt to keep your app alive as long as possible and restart it if it does get terminated. From Implementing a VoIP App:
Including the voip value in the UIBackgroundModes key lets the system
know that it should allow the app to run in the background as needed
to manage its network sockets. An app with this key is also relaunched
in the background immediately after system boot to ensure that the
VoIP services are always available.
In addition to setting this key, if you need to periodically run code to keep your voip connection alive, you can use the setKeepAliveTimeout:handler: method on UIApplication.
See also Tips for Developing a VoIP App:
There are several requirements for implementing a VoIP app:
Add the UIBackgroundModes key to your app’s Info.plist file. Set the value of this key to an array that includes the voip string.
Configure one of the app’s sockets for VoIP usage.
Before moving to the background, call the setKeepAliveTimeout:handler: method to install a handler to be
executed periodically. Your app can use this handler to maintain its
service connection.
Configure your audio session to handle transitions to and from active use.
To ensure a better user experience on iPhone, use the Core Telephony framework to adjust your behavior in relation to cell-based
phone calls; see Core Telephony Framework Reference.
To ensure good performance for your VoIP app, use the System Configuration framework to detect network changes and allow your app
to sleep as much as possible.
Almost all of the documentation you need is on the Apple developer site.
I am doing some processing when the app enters the background state, I have put it under the beginBackgroundTaskWithExpirationHandler() and thereby, should be allotted ten minutes for the same. However, I believe the app is being suspended before that. The task I am performing is memory and CPU-intensive, so is it possible that the OS is putting my app to suspend state ? If so, is there any way to bypass these restrictions. (I am open to using private API's).
Here is the code for starting the background task:
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]){
if([[UIDevice currentDevice] isMultitaskingSupported]){
__block UIBackgroundTaskIdentifier bgTask;
UIApplication *application = [UIApplication sharedApplication];
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self captureImage];
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
}
I am not sure that Daij-Dan is completely right.
This part I agree with him:
the os may kill you at any time when its pressured.
However word "pressured" is quite vague. And I believe there should be a lot of pressure (low memory as example) to suspend app which legitimately requested more time. On one hand, it's a real scenario case. On other hand, it's happening not that often (iOS devices have quite a lot of memory nowdays).
From documentation (http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html):
Each call to this method must be balanced by a matching call to the endBackgroundTask:
method. Applications running background tasks have a finite amount of time in which to run them. (You can find out how much time is available using the backgroundTimeRemaining property.) If you do not call endBackgroundTask: for each task before time expires, the system kills the application. If you provide a block object in the handler parameter, the system calls your handler before time expires to give you a chance to end the task.
I would recommend:
Add some logs in completion handler
Add logs to the logs with logic (including backgroundTimeremaining)
And if your app got suspended review system console logs.
P.S. I removed iphone-privateapi tag, since it's public API.
the os may kill you at any time when its pressured. there are no guarantees about the ten minutes.
(you can also run much longer if you behave :D)
there is no way to force ios to run your app AFAIK
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