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
Related
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;
}];
}
Can we write background service in ios which will continuously run in background after some delay (e.g 1 min).
I have an application which fetch data after every minute i want to write background service for it.
independent of application running or not,though application is not in memory, service should continuously run after 1 minute.
I have written same service in android application but i don't know it is possible or not in ios.
No you can't, iOS decides when your app can fetch.
check the "Background Fetch mode" in this article.
Well, Actualy it depend on task what you want to perform. Main point is you cant perform any task in Background permanently. at the interval of time you need to request.
You can perform few task in background like Downloading and etc. You need to use dispatch_async Something like in - (void)applicationDidEnterBackground:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// 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.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
For more Detail like finite task , you can find on apple's document in below link.
BackgroundExecution
You can also get more help regarding background services from below link.
running-background-services-in-ios
I was wondering if I could send some webservice calls while my application is in the background. How does skype do it? Even if I press the home button my call stays connected.
Building on what rckoenes stated, applications are allowed to register background tasks to be completed after the user hits the home button. There is a time limit of 10 or 15 minutes for these tasks to complete. Again, you can register a task to complete immediately after the user hits home, this does NOT allow you to execute code say an hour after they exit the app.
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;
});
UPDATE: if your app supports versions of iOS previous to iOs 4, you should also check to ensure that multitasking is supported before registering a background task. Use something along the lines of:
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:#selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;
Try This... Excellent code for running app in background with no time limit. (I tested it for downloading more than 600 mb data from web-service.)
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}
Update ::
you can found more information regarding multitaksing in this apple doc Background Execution.
Please test on device.
It depends or what kind of application are you trying to code.
Skype is registered as a VoIP (Long-running app) app and this is why it can stay "running" although it is on the background.
Apple separates apps in three:
Executing Finite-Length Tasks (you can run tasks for a finite amount of time)
Downloading Content in the Background (you can download content to present it to the user when the app becomes active again)
Implementing Long-Running Tasks (This is the most interesting background apps category, with some subcategories that the developer should define for your app)
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) (SKYPE is here)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
So, you need to evaluate in which category your app is and what your service operation performs. Maybe if you're sending some small things to the service the best approach is only to request some extra time on the background for doing the job.
More info about all of this are on this link:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
I know this is a very common question. I have read many answer but not found out the appropriate answer for me. That's why I post this question and hope someone will show me how to fix my code.
I have function startUpdate to update location using CLLocationManager. In applicationDidEnterBackground method, I write something like below:
[self startUpdate]; // position1
NSLog(#"applicationDidEnterBackground");
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
[self startUpdate]; // position2
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self startUpdate]; // position3
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://google.com"]];
});
I tried to put [self startUpdate] at one of three positions (position1, 2, 3) and sometime it works, sometime not, and I do not know why.
In case it works, updating just run in 3 minutes event. If I call startUpdate when app is in foreground, then put app to background, updating will last 15 minutes with real device, and more than 1hour with simulator ( I don't know exactly, after 1 hour, i thought it would last forever then I stop testing). So what is different between: startupdate in foreground-> go to background vs startupdate in background; simulator vs real device?
right after position3, I called following line to open safari
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://google.com"]];
But it does not work. So what types of task can be executed here, in background?
I need to keep a service running forever. Some search results say that it's impossible. But some familiar apps did that (Facebook,... keeps service to receive notifications). How can they do that?
Thank you so much,
The exact behaviour of location services has been clarified in the latest update to the Core Location documentation. It now states -
The standard location service delivers events normally while an app is
running in the foreground. When your app is in the background, this
service delivers events only when the location-updates background mode
is enabled for the app. This service does not relaunch iOS apps that
have been terminated.
The significant location change service delivers events normally while
an app is running in the foreground or background. For a terminated
iOS app, this service relaunches the app to deliver events. Use of
this service requires “Always” authorization from the user.
So, it seems that for the best chance of continuing to receive location updates in the background you should switch to significant location change monitoring once you move to the background state and restore full location monitoring once you return to the foreground.
I was wondering if I could send some webservice calls while my application is in the background. How does skype do it? Even if I press the home button my call stays connected.
Building on what rckoenes stated, applications are allowed to register background tasks to be completed after the user hits the home button. There is a time limit of 10 or 15 minutes for these tasks to complete. Again, you can register a task to complete immediately after the user hits home, this does NOT allow you to execute code say an hour after they exit the app.
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;
});
UPDATE: if your app supports versions of iOS previous to iOs 4, you should also check to ensure that multitasking is supported before registering a background task. Use something along the lines of:
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:#selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;
Try This... Excellent code for running app in background with no time limit. (I tested it for downloading more than 600 mb data from web-service.)
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}
Update ::
you can found more information regarding multitaksing in this apple doc Background Execution.
Please test on device.
It depends or what kind of application are you trying to code.
Skype is registered as a VoIP (Long-running app) app and this is why it can stay "running" although it is on the background.
Apple separates apps in three:
Executing Finite-Length Tasks (you can run tasks for a finite amount of time)
Downloading Content in the Background (you can download content to present it to the user when the app becomes active again)
Implementing Long-Running Tasks (This is the most interesting background apps category, with some subcategories that the developer should define for your app)
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) (SKYPE is here)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
So, you need to evaluate in which category your app is and what your service operation performs. Maybe if you're sending some small things to the service the best approach is only to request some extra time on the background for doing the job.
More info about all of this are on this link:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html