I am trying to collect coreMotion acceleration data in the background for longer than 10 minutes. This must be possible since apps like Sleep Cycle do this.
I just want to make sure this is allowed though, since it does not seem to be one of these:
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.
However, I have tried following these steps to get a background task, but I am thinking there is a better way for CoreMotion:
Header:
UIBackgroundTaskIdentifier bgTask;
Code:
// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {
NSLog(#"### -->VOIP backgrounding callback");
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(#"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
- (void)applicationDidEnterBackground:(UIApplication *)application {
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
{
NSLog(#"VOIP backgrounding accepted");
}
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(#"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
}
Use this one:
Apps that keep users informed of their location at all times, such as a navigation app
In other words, you make a location manager and tell it to start doing updates. You don't have to do anything with those updates! But as long as this is happening - that is, as long as your app is continuing to do location updates in the background - your app is also allowed to use Core Motion in the background. This is not just a trick; it is official Apple policy as explained in one of the WWDC videos from a couple of years ago.
Related
I have this code who send data and receive even when the application is in background mode (minimized app):
MyViewController.m
-(void)viewDidAppear:(BOOL)animated{
[self doUpdateEvenAppMinimized];
}
- (void) doUpdate{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self beginBackgroundUpdateTask];
[self sendFilesToServer];//Inside this method have a sleep that call every 5 minutes
//The code used in sendFilesToServer is the same in this website https://dcraziee.wordpress.com/2013/05/29/how-to-upload-file-on-server-in-objective-c/
//[self endBackgroundUpdateTask];//This method is forever...so I not need to call this line
});
}
- (void)beginBackgroundUpdateTask{
self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}
The documentation says that the maximum time is 10 minutes, and to remove it I use the concept of Implementing Long-Running Tasks, For that I select my project > capabilities > Background Modes (Turn On) > External accessory communication (Checked).
With these steps, my application will be exempt from the 10 minutes?
Trying to circumvent the rules to run in the background sounds like the wrong approach. Consider using NSURLSession for long running networking operations that are not tied to the lifetime of your app.
I'm developing an app which sends notifications when you are nearby of promoted places.
My problem is when I go to background and then I quit the app, I don't want the location services working when the app doesn't work (but I want them to work in background).
I saw only 3 apps which close the gps when the app is closed and I want to know how they did that, Facebook, Google Maps and Apple Maps, not Foursquare, not FieldTrips...
Thank you everybody.
you can add an observer for UIApplicationWillTerminateNotification where you start locationManager and than stop location updates
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
method to perform when you receive the notification
- (void)applicationWillTerminate:(NSNotification *)notification {
//stop location updates
}
I found the correct answer to my question becouse of #GuyS second post:
Adding that in your AppDelegate.m applicationDidEnterBackground
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:#selector(beginBackgroundTaskWithExpirationHandler:)]) {
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Synchronize the cleanup call on the main thread in case
// the task actually finishes at around the same time.
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid)
{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
});
}];
}
}
And declaring that variable:
UIBackgroundTaskIdentifier bgTask;
After that you only have to stop your location services in applicationWillTerminate...
Thank you for your replies.
The solution provided by #GuyS in this topic should work. I'm getting the UIApplicationWillTerminateNotification in case the app is in background and then I close it by swiping up the snapshot. Please check whether you work correctly with NSNotificationCenter (especially adding and removing notification). Plus, please check the object you subscribed on the notification is alive when the app is in background.
Another similar solution is to place the code that disables GPS in appropriate UIApplicationDelegate callback in your AppDelegate method.
- (void)applicationWillTerminate:(UIApplication *)application {
//stop location updates
}
I am trying to run the process in background thread . I want that process to finish in 60 secs and start running again.No matter application is in foreground or background. I don't know how to implement and where to implement it.I'm using ios7.In that process I'm also taking location updates.
I read about the background tasks, but it wasn't giving proper idea of the process. Can someone provide me with good source or link?
There is no such api given by ios for background process unlike android which use service for that.You can use timer for continuos background process .Also there is dispatch_async ,selector in background for efficient background processing.
Hope this helps.
you can use something like this for background processing,but remember apple has put restriction of 10-15 min to complete the processing.
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;
});
Also you can check the following :
**BOOL backgroundSupported = NO;
if ([device respondsToSelector:#selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;**
I am trying to collect coreMotion acceleration data in the background for longer than 10 minutes. This must be possible since apps like Sleep Cycle do this.
I just want to make sure this is allowed though, since it does not seem to be one of these:
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.
However, I have tried following these steps to get a background task, but I am thinking there is a better way for CoreMotion:
Header:
UIBackgroundTaskIdentifier bgTask;
Code:
// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {
NSLog(#"### -->VOIP backgrounding callback");
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(#"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
- (void)applicationDidEnterBackground:(UIApplication *)application {
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
{
NSLog(#"VOIP backgrounding accepted");
}
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(#"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self doSomething];
sleep(1);
}
});
}
Use this one:
Apps that keep users informed of their location at all times, such as a navigation app
In other words, you make a location manager and tell it to start doing updates. You don't have to do anything with those updates! But as long as this is happening - that is, as long as your app is continuing to do location updates in the background - your app is also allowed to use Core Motion in the background. This is not just a trick; it is official Apple policy as explained in one of the WWDC videos from a couple of years ago.
I notice in my app that when application enter background while loading causes the error such as "timeout" or "host name not found" .
It is due to the process that does not allow connection to run in background for a long time.
But that kind of error message make it bad for user experience. So what should I do to cancel the transaction ? Should I just cancel all the connection ? I tried to search the Q&A in SO here but can't find an answer.
For more information, my app use NSURLConnectionDelegate Method. I have a store singleton that manage all connection to my server. NSURLConnection is called and managed in custom object also.
I tried to just [connection cancel] in - applicationDidEnterBackground: but that make the UI broken because I load data to put into UITableViewCell ,etc. Can anyone point to the example to solve this kind of problem?
Updated Code:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
__block UIBackgroundTaskIdentifier backgroundTask; backgroundTask =
[application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid; }]; }
}
Can I just put this code in the appDelegate ? What is the drawback for just doing this versus put the beginBackgroundTaskWithExpirationHandler before the task that I want to keep running in background and endBackgroundTask after that task finished ? My code has one object that deal directly to NSURLConnection.
You are allowed to keep running an NSURLConnection for some period of time after you go into the background. Apple doesn't publish the exact period of time, but it's 10 minutes. See Executing a Finite-Length Task in the Background for details on how to use beginBackgroundTaskWithExpirationHandler: to request more time to complete your download.
In most cases you shouldn't proactively cancel your download. You should wait until the system expires you and then deal with the error at that point. If your download is brief, there's no reason to cancel it (in most cases, the most expensive thing about a connection is setting it up in the first place). If it's a very long download, then the user is going to be annoyed if it doesn't proceed in the background. (This assumes that you're downloading things because the user requested it.)
First, it's better to have this call on the application delegate, so that the View in the NavigationController can be closed. Second, mark beginning of the background processing with beginBackgroundTaskWithExpirationHandler: and end it with endBackgroundTask: like this:
.h:
UIBackgroundTaskIdentifier bgTask;
.m:
- (void)sendPhoto:(UIImage *)image
{
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
NSLog(#"Sending picture...");
// Init async NSURLConnection
// ....
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Picture sent.");
UIApplication *app = [UIApplication sharedApplication];
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
}
Also remember one thing its important:
You have 10 minutes before iOS terminates your app. You can check this time with [app backgroundTimeRemaining]