I have been working on an app in which user can record video using AVFoundation and send to the server, video has maximum size up to 15M, depending on the internet speed & type it can take from 1 to 5 minutes approximately to transfer video to the server. I am transferring the recorded video to the server in the background thread so that user can continue other stuff on the app while video is being uploaded to the server.
While reading the Apple Docs for implementing long running tasks in backround, I see that only few kinds of apps are allowed to execute in the background.
e.g.
audio—The app plays audible content to the user while in the background. (This content includes streaming audio or video content using AirPlay.)
Does it qualify my app also for running the tasks in the background? or I need to transfer the video on the main thread?
NSOperationQueue is the recommended way to perform multi-threaded tasks to avoid blocking the main thread. Background thread is used for tasks that you want to perform while your application is inactive, like GPS indications or Audio streaming.
If your application is running in foreground, you don't need background thread at all.
For simple tasks, you can add a operation to a queue using a block:
NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperationWithBlock:^{
// Perform long-running tasks without blocking main thread
}];
More info about NSOperationQueue and how to use it.
The upload process will continue while in background, but your application will be eligible to be suspended, and thus the upload may cancel. To avoid it, you can add the following code to application delegate to tell the OS when the App is ready to be suspended:
- (void)applicationWillResignActive:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Wait until the pending operations finish
[operationQueue waitUntilAllOperationsAreFinished];
[application endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}
From your response to Dwayne, you do not need to be able to download in background mode. Rather what you need is to do your download in another thread (background thread) beside main thread. Something like this for GCD:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do you download here...
});
Your requirement qualifies to run in background. You do not need to register any background modes supported in the info plist. All you need to do is, when the app is about to go into background, request for additional time using background task handler and perform your task in that block. Make sure you stop your handler before 10 mins so as to not get force terminated by the OS.
You may use the below code from Apple.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
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.
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;
});}
Related
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
So I am trying to do a simple POST request when my app closes down.
I've tried [NSURLConnection sendAsynchronousRequest]
and doing [NSURLConnection sendSynchronousRequest] with dispatch_async. The only thing that actually works as I want is to do the synchronous request on the main thread, but then it lags, especially if the server is slow to respond.
Both kind of work, except they send the actual request when the app opens again, instead of when it closes. I am currently doing this in applicationDidEnterBackground but I've tried applicationWillResignActive also.
I have set the Application does not run in background in the apps info.plist also. No change.
I could do all things when the app opens. But the code will be nicer if I can achieve it when closing the application.
Is it possible?
From the documentation for applicationDidEnterBackground -
it's likely any background tasks you start in
applicationDidEnterBackground: will not run until after that method
exits, you should request additional background execution time before
starting those tasks. In other words, first call
beginBackgroundTaskWithExpirationHandler: and then run the task on a
dispatch queue or secondary thread.
So, you are requesting an asynchronous operation, but this task won't execute before applicationDidEnterBackground returns, and once this method returns your application will no longer be active. The tasks are sitting there and run once your app returns to the foreground.
The iOS programming guide provides advice on executing a task when your app moves to the background
You will need something like -
- (void)applicationDidEnterBackground:(UIApplication *)application
{
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.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task
[NSURLConnection sendSynchronousEvent....];
// TODO process results..
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
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
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