When I launch my app I check current location authorisation status like this:
- (void)checkCurrentStatus
{
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
[self.locationManager requestWhenInUseAuthorization];
}
else
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied && ![CLLocationManager locationServicesEnabled])
{
[self.locationManager startUpdatingLocation];
}
}
If overall location services are enabled (for the whole device) than it just asks user for permission, the alert pops up. If they are disabled (else if condition) then I need to call startUpdatingLocation because call to [self.locationManager requestWhenInUseAuthorization]; has no effect when authorisation status is kCLAuthorizationStatusDenied (without any if conditions). Ok, so I call startUpdatingLocation and then alert pops up which says:
Turn On Location Services to Allow "AppName" to Determine Your Location
Ok, I go to the settings on turn overall location services on. After that authorizationStatus becomes kCLAuthorizationStatusNotDetermined but when I call requestWhenInUseAuthorization it has no effect! No popup appears, user is not prompted for to authorise location, the status remains the same, I can't use location manager. How can I handle that?
From Apple's doc on CLLocationManager about - (void)requestWhenInUseAuthorization
If the current authorization status is anything other than
kCLAuthorizationStatusNotDetermined, this method does nothing and does
not call the locationManager:didChangeAuthorizationStatus: method
Here's what you need :
- (void)requestAlwaysAuthorization
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// If the status is denied or only granted for when in use, display an alert
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusDenied) {
NSString *title;
title = (status == kCLAuthorizationStatusDenied) ? #"Location services are off" : #"Background location is not enabled";
NSString *message = #"To use background location you must turn on 'Always' in the Location Services Settings";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Settings", nil];
[alertView show];
}
// The user has not enabled any location services. Request background authorization.
else if (status == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestAlwaysAuthorization];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
// Send the user to the Settings for this app
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL];
}
}
Courtesy copy of this blog post
Related
Location services stopped working after I uninstalled my iOS10 app. I have the description set up in the Info.plist so it confuses me why location services would stop working. The app does not show up in Settings->Privacy->Location Services
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs to use your location so that it may send it to your selected contacts.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs to use your location so that it may send it to your selected contacts.</string>
Checking for status using the following code reveals that the status is Not Determined.
if ([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) {
NSLog(#"RESTRICTED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
NSLog(#"DENIED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
NSLog(#"NOT DETERMINED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"ALWAYS");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
NSLog(#"WHEN IN USE");
}
}
EDIT:
The viewController viewDidLoad method contains the following code:
- (void)viewDidLoad {
[self.locationManager requestAlwaysAuthorization];
[self.locationManager requestWhenInUseAuthorization];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
if ([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) {
NSLog(#"RESTRICTED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
NSLog(#"DENIED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
NSLog(#"NOT DETERMINED");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) {
NSLog(#"ALWAYS");
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
NSLog(#"WHEN IN USE");
}
}
}
You need to use [yourLocationManager startUpdatingLocation] which will prompt the alert for Using location.
Until then authorizationStatus will be kCLAuthorizationStatusNotDetermined
Edit
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager requestAlwaysAuthorization];
self.locationManager.delegate = self;
Add this
You need to check authorization status, and if it's xxx, you need to call requestAlwaysAuthorization() or requestWhenInUseAuthorization(). That will trigger an alert to the user.
If you've deleted the app by long-pressing the app icon and tapping the X, that revokes the user's permission to use location services, so the app will be denied access until you call requestAlwaysAuthorization() or requestWhenInUseAuthorization() again.
I require location of the user in my application if in case the user has device location services disabled I am checking like this.
if([CLLocationManager locationServicesEnabled])
{
if([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[locationManager requestWhenInUseAuthorization];
}
}
else if(![CLLocationManager locationServicesEnabled])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Location Services are disabled please enable location services to enjoy nearby experience" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Settings", nil];
alert.tag = 103;
[alert show];
}
In my alert view I am directing the user to location settings like this
else if(alertView.tag == 103)
{
if(buttonIndex == 1)
{
NSURL*url=[NSURL URLWithString:#"prefs:root=LOCATION_SERVICES"];
[[UIApplication sharedApplication] openURL:url];
}
}
After the user comes back from settings how to get location again
You can manage your stuff in applicationWillEnterForeground because this method will get called when you come from setting app to your app.
You can write your code in this method like,
if([CLLocationManager locationServicesEnabled])
{
if([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[locationManager requestWhenInUseAuthorization];
}
}
Use Location Delegate method :-
if([CLLocationManager locationServicesEnabled])
{
if([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[locationManager requestWhenInUseAuthorization];
//Set Location Delegate
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//Update Location start
[locationManager startUpdatingLocation];
}
}
else if(![CLLocationManager locationServicesEnabled])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Location Services are disabled please enable location services to enjoy nearby experience" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Settings", nil];
alert.tag = 103;
[alert show];
}
#pragma mark CLLocationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//NSLog(#"OldLocation %f %f", oldLocation.coordinate.latitude, oldLocation.coordinate.longitude);
//NSLog(#"NewLocation %f %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
[locationManager stopUpdatingLocation];
}
I kept Guided Access for iPad app. When the app is launched it asks for user's current location using CLLocationManager.This is working under Normal mode and updates user current location. But under Guided Access, popup ("Allow to access your location") is not shown and authorizationStatus is always kCLAuthorizationStatusNotDetermined and doesn't update current location of user . Couldn't understand what could be the problem.Searched a lot but couldn't find it.
ViewController.m :
- (void)viewDidAppear:(BOOL)animated
{
[appDelegate startLocation];
[self performSelector:#selector(CheckLocationManger) withObject:nil afterDelay:0.1];
}
-(void)CheckLocationManger
{
AppAppDelegate *appDelegate=(AppAppDelegate*)[[UIApplication sharedApplication]delegate];
if(![CLLocationManager locationServicesEnabled])
{
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"Whoops we can’t find you!" message:#"Location services are disabled" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
if(activityIndictr)
[activityIndictr stopAnimating];
[alert1 show];
return;
}
if([CLLocationManager locationServicesEnabled])
{
if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied)
{
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"Whoops we can’t find you!"message:#"Location services are disabled. You can fix this by going to Settings > Privacy > Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
if(activityIndictr)
[activityIndictr stopAnimating];
[alert1 show];
return;
}
if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined) //This is called
{
[self performSelector:#selector(CheckLocationManger) withObject:self afterDelay:0.1];
return;
}
}
if(![self connected])
{
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"Please verify that you have internet connectivity" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
if(activityIndictr)
[activityIndictr stopAnimating];
[alert1 show];
[alert1 release];
return;
}
else {
//continue further process
}
}
AppDelegate.m
- (void)startLocation
{
self.locationManager = [[[CLLocationManager alloc] init]autorelease];
self.locationManager.pausesLocationUpdatesAutomatically=NO;
[self.locationManager setDelegate:self];
if([[[UIDevice currentDevice ]systemVersion] floatValue]>=8.0)
{
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization]; //is executed but popup never displays
}
}
[self.locationManager startUpdatingLocation];
}
Any suggestions would be helpful.Thank you !
At very first set NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in your .plist.
Add CoreLocation.framework and import in your class.h file -> #import <CoreLocation/CoreLocation.h> then set CLLocationManagerDelegate to your class.
Declare #property (strong, nonatomic) CLLocationManager *locationManager;
Init locationManager and set default value to it.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[self.locationManager setDistanceFilter:200.0f];
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) // Or if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
[self.locationManager requestAlwaysAuthorization]; // Or [self.locationManager requestWhenInUseAuthorization];
[self.locationManager startUpdatingLocation];
Implement CLLocationMAnager delegate method
#pragma mark - Location Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"updated coordinate are %#", [locations lastObject]);
CLLocation *currentLocation = [locations lastObject];
// Your code.....
}
I am trying to update some old code to get it to work in IOS 8. I have read through
Location Services not working in iOS 8
but I am still very confused as to how to correctly implement the methodology.
I have added in
<key>NSLocationWhenInUseUsageDescription</key>
<string>The spirit of stack overflow is coders helping coders</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I have learned more on stack overflow than anything else</string>
into the infoPlist.strings
but I am not sure how to update my code to get it to execute properly. Here is a copy of the old code that I am using. Can anyone provide insight on how to properly update this code in order to get it to work with IOS 8?
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSLog(#"%s", __PRETTY_FUNCTION__);
switch (status) {
case kCLAuthorizationStatusAuthorizedAlways:
{
NSLog(#"kCLAuthorizationStatusAuthorized");
// Re-enable the post button if it was disabled before.
self.navigationItem.rightBarButtonItem.enabled = YES;
[self.locationManager startUpdatingLocation];
}
break;
case kCLAuthorizationStatusDenied:
NSLog(#"kCLAuthorizationStatusDenied");
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Anywall can’t access your current location.\n\nTo view nearby posts or create a post at your current location, turn on access for Anywall to your location in the Settings app under Location Services." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertView show];
// Disable the post button.
self.navigationItem.rightBarButtonItem.enabled = NO;
}
break;
case kCLAuthorizationStatusNotDetermined:
{
NSLog(#"kCLAuthorizationStatusNotDetermined");
}
break;
case kCLAuthorizationStatusRestricted:
{
NSLog(#"kCLAuthorizationStatusRestricted");
}
break;
}
}
The code I am using here is from an old version of parse's Anywall Tutorial. I have tried adding in
case kCLAuthorizationStatusNotDetermined:
{
NSLog(#"kCLAuthorizationStatusNotDetermined");
[self.locationManager requestAlwaysAuthorization];
}
break;
In addition the application also displays the user's location on a map do I have to update that method as well?
You have to do it like this:
1)#import <CoreLocation/CoreLocation.h>
2)Set delegate CLLocationManagerDelegate
3)Create CLLocationManager *locationManager; Object
4)#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) in your .m file
5)Setup location manager
if (self.locationManager==nil) {
self.locationManager = [[CLLocationManager alloc]init];
}
self.locationManager.delegate = self;
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// If the status is denied or only granted for when in use, display an alert
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusDenied || status == kCLAuthorizationStatusRestricted) {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0"))
{
NSString *title;
title = (status == kCLAuthorizationStatusDenied) ? #"Location services are off" : #"Background location is not enabled";
NSString *message = #"To use background location you must turn on 'Always' in the Location Services Settings";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Settings", nil];
[alertView setTag:1001];
[alertView show];
[alertView release];
}
else{
NSString *titles;
titles = #"Title";
NSString *msg = #"Location services are off. To use location services you must turn on 'Always' in the Location Services Settings from Click on 'Settings' > 'Privacy' > 'Location Services'. Enable the 'Location Services' ('ON')";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:titles
message:msg
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
}
// The user has not enabled any location services. Request background authorization.
else if (status == kCLAuthorizationStatusNotDetermined) {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0"))
{
[self.locationManager requestAlwaysAuthorization];
}
}
[self.locationManager startUpdatingLocation];
6)Setup alert view for iOS 8
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag==1001){
if (buttonIndex == 1) {
// Send the user to the Settings for this app
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL];
}
}
}
Please don't mark it as duplicate because I took help from others posted answer in stack overflow. But still I faced some issues. Location manager delegate not get called even in real device also. And also it's not asking for the permission.
Below is my code.
- (IBAction)getUserLocationAction:(id)sender
{
if([CLLocationManager locationServicesEnabled])
{
if(!locationManager)
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
//[locationManager startMonitoringSignificantLocationChanges];
}
else
{
NSLog(#"Location service is not enabled");
}
}
#pragma mark - Location Manager Delegate-
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%#", locations);
userLocation = [locations lastObject];
NSLog(#"User Current Locatiion\nLat: %+.6f\nLong: %+.6f", [userLocation coordinate].latitude, [userLocation coordinate].longitude);
[locationManager stopUpdatingLocation];
//[locationManager stopMonitoringSignificantLocationChanges];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"Error: %#", [error localizedDescription]);
}
I also add the below two key in my .plist file
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app want to use your location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app want to use your location</string>
I have also added the frameworks
I am not sure where I am doing wrong. Please help me.
UPDATE
Firstly I think its an issue with my code but after some research it's working as expected in iOS7. The code is remain same, this issue occur only in iOS8. Please let me know what changes needs to be done for working in iOS8 also.
You need to do some more checking:
- (IBAction)getUserLocationAction:(id)sender
{
if([CLLocationManager locationServicesEnabled]) {
if(!self.locationManager) {
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus];
if (authStatus == kCLAuthorizationStatusNotDetermined) {
// Check for iOS 8 method
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
else {
[self.locationManager startUpdatingLocation];
}
}
else if(authStatus == kCLAuthorizationStatusAuthorizedAlways || authStatus == kCLAuthorizationStatusAuthorizedWhenInUse || authStatus == kCLAuthorizationStatusAuthorized) {
[self.locationManager startUpdatingLocation];
}
else if(authStatus == kCLAuthorizationStatusDenied){
NSLog(#"User did not allow location tracking.");
// present some dialog that you want the location.
}
else {
// kCLAuthorizationStatusRestricted
// restriction on the device do not allow location tracking.
}
}
else {
NSLog(#"Location service is not enabled");
}
}
Also you need to handle the use callback:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status != kCLAuthorizationStatusRestricted && status !=kCLAuthorizationStatusDenied) {
[self.locationManager startUpdatingLocation];
}
}
Check your Location Access settings..so go to Setting-->Privacy-->Location Services-->Your app