iOS7.1 LocationManager pausing when entering background (works in 7.0) - ios

Slightly confused on this one so I broke it down to a test app.
Simple singleton handling locationManager. I have turned on location support in the background under capabilities. Map is also enabled.
The location manager is running all the time but as soon as I put the application in to the background, it pauses.
I have read many posts about people trying to start location manager in the background, but mine is already running. I assumed by enabling it under capabilities, it would continue to run in the background. As soon as the app resumes, so does location manager.
Do I need to start looking in to beginBackgroundTaskWithExpirationHandler?
UPDATE
The code works in 7.06 and not 7.1.1? what did they change?

I believe you must set your applications background modes to allow location updates. To do this edit your apps .plist file and add "location" as a "Required background mode" see the Apple docs for more background modes (here)

in appDelegete.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[locationmanger startUpdatingLocation];//start your location update method here
//then add this code
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundTask];
}];
}
-(void) endBackgroundTask
{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}
it will work now

Related

iOS: Long-Running task

This is the example from developer.apple.com
Finite-Length Tasks
Starting a background task at quit time
- (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;
});
}
I want to implement the Long-Running Task, not the "Finite-Length" one. I've not found any examples written with objective-c for current version sdk. Can I start it, say, on application start and run it continuously wheter app is in foreground or background? How do i do that?
I'm a react-native developer, and i've just begun learning objective-c. Therefore i may need just simple example to follow. I've already implemented bridge instance to Cocoa Touch Class, it works fine. All i need is to launch the Long-Running Task in this class. I need it for BLE, but for sake of simplicity, i'd say, let's use location tracking, as it's easier and quicker to test.
My LongRunningTask.m:
#import "LongRunningTask.h"
#implementation LongRunningTask
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(start:(RCTResponseSenderBlock)callback)
{
// start the Long-Running Task here
callback(#[#"done"]);
}
I don't get it, how is long-running task being defined? Seems, there is no specific method or any marker, which would declare a task to be long-running. So, technically, if i'm getting permission from user to run a specific type of long-running task, i can continuously run whatever code i want within applicationDidEnterBackground? Even if it has nothing in common with the permission i've got?
And the only factor that affects if this task will be terminated in 10-ish minutes is if i've got the permission or not?
Thank you!
For the term Long-Running Task means the task which is active until the app has been killed, I am giving you simple example of LocationManager
When you setup your app to receive Location Updates and initialize the LocationManager the app is subjected to receive location updates until you stop the updates in foreground, same is the case with BLE.
See the examples,
_locationManager=[[CLLocationManager alloc] init];
_locationManager.delegate=self;
if ([_locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
[_locationManager requestAlwaysAuthorization];
}
[_locationManager startUpdatingLocation];
The above code starts the LocationManager for the app to receive GPS location updates if the user has given permission to the app to receive GPS location and if the GPS settings for app is ON to receive updates, the method below will get called till your app is in Foreground
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
Same happens with BLE
If you want your app to be able to receive GPS or, BLE updates in Background you need to turn on related Background Modes from the Project Settings of the app as shown below in the image
The image shows the list of services you can run while app in background, apart from the list you can do certain network activities like downloads and uploads which you have shown in your example, which will run a Long-Running Task, until you kill the app, or the service is interrupted from settings by user manually.
Hope above clears your doubt.
Cheers.

Long running background task in iOS

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.

How to run location updates in background continuously in ios

UIApplication* app = [UIApplication sharedApplication];
_backgroundTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:_backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
}];
[self startTimer];
NSLog(#"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
-(void)startTimer
{
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:#selector(repeatedMethod)
userInfo:nil
repeats:YES];
}
I'm able to run successfully when my app is in foreground but when I come to background if
backgroundTimeRemaining:10 it is running for 3 minutes but when backgroundTimeRemaining:176
it is running continuously. One thing I did not understand is why backgroundTimeRemaining is showing different numbers.How to run process continuously in Background. One thing I need to mention is my background process contains location updates. I'm very new to ios. Any help would be appreciable.
You need to set below key values in your app's info.plist file
Required background modes : App registers for location updates!
As shown in below image and implement you location manager delegate methods in AppDelegate so that its there even your app is in any view controller.
Setting the above key value in info.plist will tell ios to enable background mode for location services.
Read "Getting Location Events in the Background (iOS Only)" in:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW10
Basically your app needs to ask for permission to have a background mode for this, and use the location APIs rather than a time. You'll do some setup (get default location manager, set a delegate), call "startUpdatingLocation" from the CLLocationManager class, and then get periodic callbacks with new locations.
Keep in mind you'll drain the user's phone battery pretty fast if you do this, and Apple will reject your app from the App Store unless you give a disclaimer about this.
Set your CLLocationManager's pausesLocationUpdatesAutomatically to NO. It may help you.
For more info check Apple's Location manger documentation.

how much time UIApplication is going to run in the background state

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.

How is it possible to ensure a constant continuous update of location when iOS app is in the background?

One requirement for our iOS app is to monitor location changes in the background. We have implemented "locationManager startMonitoringForRegion:region", unfortunately we realised when testing the app thoroughly that it is too little precise to fulfil our needs.
We then used "locationManager startUpdatingLocation" to increase accuracy of location. In the foreground everything worked out quite good, this location precision is pretty much what we want.
Now the problem is when the app is in the background, the event "didUpdateLocations" is not called on regular basis. We observed this by looking into log file. What happens is pretty much always the same, the first 15 minutes the app updates the location regularly and then suddenly abruptly stops. After about a 5 minute break it carries on with updating the location for again about 15 minutes. And this continues on in the same way.
We probably made the mistake in the implementation in background handling.
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
if(rootViewController._selectedLocation == nil)
{
NSLog(#"selected location is nil and app entered background");
[rootViewController.locationManager stopUpdatingLocation];
}
else
{
NSLog(#"selected location is not nil and app entered background");
[rootViewController.locationManager startUpdatingLocation];
}
[app endBackgroundTask:bgTask];
}];
This seem to be called about every 20 minutes and the location is updated again. What are we doing wrong and how can we get a regular location update without any interruptions? We tested this with iPhone 5 and also important to know it was stationary.
You should add to your application plist file the following value:
Required background modes
It is an array telling the system what you app need when in background. For the position at item 0, you should inform the value:
App registers for location updates
In case of doubt, you can see in this link what I'm talking about: iOS Multitasking: Background Location

Resources