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
Related
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.
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 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;
});}
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