How to enable "When app in use" in CLLocationManager in iOS 8 - ios

I just became aware of a new privacy option for Location Service in iOS 8 which allows the user to select "When app in use" as privacy option.
My application needs to go back to iOS 7, and I can't figure out how to make this option available for my application. Currently it just says "Always/Never"
I am not doing anything special in the code. Location Services are started using
startUpdatingLocation
when in the foreground, and
startMonitoringSignificantLocationChanges
when in the background.
I also tried implementing
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
to no avail.
Any ideas?

With iOS 8 you must add a new value to your plist, either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription. If you want a specific message to show when the alert is displayed to the user, you can set the string as the value to the location key.
Also you must add this code to actually ask the user the permission, switch out the function with whichever key you used in your plist.
#pragma message ("iOS 8 Support for location updating")
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]){
[self.locationManager requestWhenInUseAuthorization];
}
More information https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/

Related

iOS GPS tracking app that runs all the time

I am trying to make an app to track the user GPS all the time, this app is a kind of car GPS tracker to get the location of driver all the time and send it to server.
I have tried to add "location updates" to the "background modes" but the app will automatically suspends after 10 mins when going into background.
Is there a way to make this app run all the time and get the GPS location?
You have two options here:
1) Regular location tracking. This type of tracking works with kCLAuthorizationStatusAuthorizedWhenInUse and kCLAuthorizationStatusAuthorizedAlways authorizations. When CLLocationManager started tracking location once it will receive location updates in delegate method locationManager:didUpdateLocations:. App can go to suspended state, but when location manager receive new location app goes to background state and handles new location in delegate method. How to setup location manager:
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
// Setup location tracker accuracy
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
// Distance filter
self.locationManager.distanceFilter = 50.f;
// Assign location tracker delegate
self.locationManager.delegate = self;
// This setup pauses location manager if location wasn't changed
[self.locationManager setPausesLocationUpdatesAutomatically:YES];
// For iOS9 we have to call this method if we want to receive location updates in background mode
if([self.locationManager respondsToSelector:#selector(allowsBackgroundLocationUpdates)]){
[self.locationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.locationManager startUpdatingLocation];
}
2) Signification location changes tracking. This type of tracking works only with kCLAuthorizationStatusAuthorizedAlways authorization. It receives new location only each 500 meters, so distance filter and desiredAccuracy don't work here. App can go to suspended state, and even can be terminated by system, but when location updates app goes to background state and receives location in delegate method locationManager:didUpdateLocations:.If app was terminated by system, it will be relaunched in background with UIApplicationLaunchOptionsLocationKey key in launch options in didFinishLaunchingWithOptions app delegate method. How to setup this type on tracking:
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
// Assign location tracker delegate
self.locationManager.delegate = self;
// For iOS9 we have to call this method if we want to receive location updates in background mode
if([self.locationManager respondsToSelector:#selector(allowsBackgroundLocationUpdates)]){
[self.locationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.locationManager startMonitoringSignificantLocationChanges];
}
You should notice that both of these methods does not guarantee that your application does not go to suspended state.
Also, if app was terminated by user (for example from app switcher by swipe) location tracking in background will not work.
UPDATE (corresponding to comments)
Here is my code examples that work for me:
For Regular tracking. Run the example, provide access to user location, tap Start button to start location updates. To test locations in simulator choose in simulator menu Debug > Location > Freeway Drive. Now you can push app to background by home button (Command+Shift+H). Leave simulator for more than 10 minutes, and all this time app will receive locations. When you return to app you will see red pins on the map.
For Significant changes. Run the app and test by the same way as for previous example.
Monitoring Significant changes can be started only by method [self.locationManager startMonitoringSignificantLocationChanges];
UPDATE (iOS 11)
Changes to location tracking in iOS 11
iOS 11 also makes some major changes to existing APIs. One of the affected areas is location tracking. If your app only uses location while the app is in the foreground, as most apps do, you might not have to change anything at all; however, if it’s one of those apps that continuously track user’s location throughout the day, you should probably book some time this summer for making some changes in how you do the tracking and testing possible usage scenarios.
follow this link: https://mackuba.eu/2017/07/13/changes-to-location-tracking-in-ios-11/
I am sure it is useful for the author because the question was asked in Feb 2016 and I am giving an answer in June 2019. This answer maybe is useful for other users.
Recently, I was working with the same requirement. After 2-3 week hard work, I did it. For other users, I create a helper class for it. Which is available in GitHub.
Please use HSLocationManager for your requirement. I have achieved the same requirements in one of my project
Location manager that allows getting background location updates every
n seconds with desired location accuracy.
Advantage:
OS will never kill our app if the location manager is currently
running.
Give periodically location update when it required(range is between 2 -
170 seconds (limited by max allowed background task time))
Customizable location accuracy and time period.
Low memory consumption(Singleton class)
In reply to comment 1 in the solution (I can't comment anywhere yet): you didn't seem to solve the problem as your app gets suspended and doesn't update the location any more after 10 minutes.
I had the same issue: I had set setAllowsBackgroundLocationUpdates to YES, and I had the NSLocationAlwaysUsageDescription key in my Info.plist, but my App also used to stop tracking location after 10 minutes.
I solved it by adding both NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription to the Info.plist file so it looks like this:
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs to use your location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs to use your location</string>
set it.it take power of battery but your application run in Background.OS does not Suspend your App
[self.locationManager setPausesLocationUpdatesAutomatically:NO];

Request location updates permissions iOS

I currently have my app setup to request location services always, using [locationManager requestAlwaysAuthorization]; and NSLocationAlwaysUsageDescription
This works fine, however I would like to give the option of using location services only while using the app like in the screenshot below.
I have tried adding NSLocationWhenInUseUsageDescription however this overides he always request and only gives the alert for while in use, any ideas on who to give both options in settings?
First ask the user using your own dialog with two options - always / when using the app. Then call appropriate permission request according to the user's choice.
Either:
[locationManager requestAlwaysAuthorization];
or:
[locationManager requestWhenInUseAuthorization];
having both in plist is valid so that's not a problem. Depends on when you actually request it in the code.
It will be slightly tricky to maintain though, so a good code structure is crucial.
The built in iOS alert will only allows for one level of permission and it will only ask the user once. The assumption is that most apps will only need one or the other. In any case, if you want to have both options show up in the Settings, you must ask for Always permission.
More importantly though:
The Always setting is really only to be used by apps that require background location updates. So unless your app requires it, you shouldn't be asking for it. Also, using background location mode will cause your app to be more heavily scrutinized during the app review process.

SignificantLocationChanges doesn't work since iOS 8

I have a problem with the SignificantLocationChanges since the release of iOS 8. The method
[locationManager startMonitoringSignificantLocationChanges];
is called correctly after checking for availability, the delegates also work nice (I check it with the didChangeAuthorizationStatus method, which is part of the same delegate and object) and compiler has no doubts, but there comes absolutely no updates and no errors from the didFailWithError method. The log says the authorizationStatus is 4, which is ok I think.
Before iOS 8 this all works fine.
The first test-device (iPad 2 with 3G) runs iOS 7.1.2 the second (iPhone 5) 8.0.2, when I use the normal startUpdatingLocation method I get updates immediately. But SignificantLocationChanges would be much better for my work. Has anyone an idea where the error could be?
In iOS 8 You must request authorization with type "Always" to allow your app to use significant locations.
Add a new row in your -Info.plist file with key NSLocationAlwaysUsageDescription
Then request authorization if its not requested yet.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusNotDetermined && [manager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[manager requestAlwaysAuthorization];
}
}
I'm having problems with startMonitoringSignificantLocationChanges too..
I added the [self.locationManager requestWhenInUseAuthorization]; and added the NSLocationWhenInUseUsageDescription string to the plist file.
When i run my app everything works, the didChangeAuthorizationStatus delegate method called, but no activity to the didUpdateLocation or didFailWithError delegate methods..
But when i switch to startUpdatingLocation, magically it works! But i need startMonitoringSignificantLocationChanges to work because i dont want my app to consume battery for an event that i dont need!
UPDATE!! Problem Solved!
Oh i see why it does not working now!. The new SDK reference here in this link says;
"You must call this method or the requestAlwaysAuthorization method prior to using location services. If the user grants “when-in-use” authorization to your app, your app can start most (but not all) location services while it is in the foreground. (Apps cannot use any services that automatically relaunch the app, such as region monitoring or the significant location change service.)"
So it is not possible to use startMonitoringSignificantLocationChanges with the [self.locationManager requestWhenInUseAuthorization]; method. You have to use requestAlwaysAuthorization instead!
Have you remembered to call method
-requestAlwaysAuthorization
(or -requestWhenInUseAuthorization)
on your CLLocationManager? This is a new method in iOS 8, and it's required to call it before starting location updates.
Also, double check if you're allocating and calling -startUpdatingLocation on the main thread. I'm not sure about that one, but I think calling it on a different thread could cause problems.

Access the user's location on Today Extension

Is it possible to access the user's location on a widget?
I used the new iOS 8 API
[locationManager requestWhenInUseAuthorization];
and I added to the info.plist file the key
NSLocationWhenInUseDescription
however, when I request the location access, an alert should appear, but it doesn't happen.
Are there some not declared limitations on iOS today extensions?
As I found out, didUpdateLocations: delegate method doesn't work in today extension. So, to get location use locationManager.location.
Along with requesting authorization, you must also explicitly ask your location manager to start updating locations.
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
The key NSLocationWhenInUseDescription is wrong, therefore the Alert doesn't come up.
Change it to NSLocationWhenInUseUsageDescription and it should work.
For all keys you can refer to this:
https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html
The authorization dialog does not pop up in extensions. Your app, which should be in the same App Group (in capabilities)

didUpdateToLocation alert called only twice

Suppose in the starting the location services are off in the default settings page. I have a button in the app to turn on the location services if first time I click on that it shows the default alert to change the settings to turn on
locationmanager = [[CLLocationManager alloc]init];
[locationmanager setDelegate:self];
[locationmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationmanager startUpdatingLocation];
It is working fine two times. but if it got third time location services are in off condition and click on on button it doesn't show any alert. I am unable to know the CLLocation behavior. May b its not a good question to ask but still I want to clear this concept. if anyone has some idea then please help me out.
Thank You.
Here's what Apple documentation says:
In addition to hardware not being available, the user has the option of denying an application’s access to location service data. During its initial uses by an application, the Core Location framework prompts the user to confirm that using the location service is acceptable. If the user denies the request, the CLLocationManager object reports an appropriate error to its delegate during future requests. You can also check the application’s explicit authorization status using the authorizationStatus method.
So the alert could or could not appear, based on authorizationStatus.

Resources