Location Services not working in iOS 8
Asked Answered
L

26

623

My app that worked fine on iOS 7 doesn't work with the iOS 8 SDK.

CLLocationManager doesn't return a location, and I don't see my app under Settings -> Location Services either. I did a Google search on the issue, but nothing came up. What could be wrong?

Liberalize answered 5/6, 2014 at 14:12 Comment(7)
You can also use this as reference app for the solution github.com/jbanford/ConstantLocationUpdatesIrrationality
I posted about some of the changes to the location manager in iOS 8 here: nevan.net/2014/09/core-location-manager-changes-in-ios-8Obstipation
You could try using this library which simplifies the Core Location APIs and exposes a nice blocks based interface, and normalises all the differences between different iOS versions (Full disclosure: I'm the author): github.com/lmirosevic/GBLocationHaiku
I found some reference here datacalculation.blogspot.in/2014/11/…Amerind
you can refer this post with #25911830Jacinthe
@nevanking You sir! need a crown! I have been fighting with this problem since change and have yet to find an "guide" how to fix it, that was noob friendly.. Your guide made an idiot like me, handle the problem my self. Thank you so much for that link.Armin
You can refer this link : iOS: Core Location is not asking user's permissionChristy
L
1097

I ended up solving my own problem.

Apparently in iOS 8 SDK, requestAlwaysAuthorization (for background location) or requestWhenInUseAuthorization (location only when foreground) call on CLLocationManager is needed before starting location updates.

There also needs to be NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in Info.plist with a message to be displayed in the prompt. Adding these solved my problem.

enter image description here

For more extensive information, have a look at: Core-Location-Manager-Changes-in-ios-8

Liberalize answered 5/6, 2014 at 14:58 Comment(23)
This is of course not a solution for apps built against the iOS 7 SDK as required for submitting to the App Store now. I've filed rdar://17465666: openradar.appspot.com/17465666Rounds
So if I use MapKit, i will have to us CLLocation to make the request?Moorish
can you share the exact valur u updated in Info.plist? Iam not able to see that key in my Info.plist. I added it and still it does not seem to work. I am using Swift, iOS8 and XCode 6 beta 4Elvinaelvira
Nice one! Additional "gotcha": although iOS 8 docs say that didChangeAuthorizationStatus will only get called for changes, that's not true. For me in iOS 8 beta 5 on an iP5, it gets called multiple times, first with status kCéAuthorizationStatusNotDetermined, which is odd.Acetamide
@Vjay - you have to edit the Info.plist file in an editor, cannot set those keys in Xcode (as of beta 6).Rockoon
Hey its not working in my case :( Please help me to modify Info.Plist by using NSLocationWhenInUseUsageDescription ...Spitler
Just a reminder, if you don't wanna show custom explanation to the user, just set this key to an empty string.Poncho
How can I localize it ?Selfmade
@KendallHelmstetterGelner why is that? You're right, it works for me to edit Info.plist but not if set in Xcode.Jollification
You need to retain your locationManager to make it work. so make your CLLocationManager as a strong propertyPeltry
I 'LOVE' that you get no error, no warning, no log message, NOTHING if you leave out the plist entry. Basically Apple has created an API call that does NOTHING if you don't have the appropriate plist entry. Thanks to @OrtwinGentz for figuring this out.Gilliam
I found that I had to add both keys regardless of which auth I called to CLLocationManager.Lombard
Here is the relevant PDF from WWDC 2014 that describes the changes that developers need to implement (pp 108 and 116): devstreaming.apple.com/videos/wwdc/2014/706xxjytntg51wd/706/…Unharness
@özg If the messages for NSLocationWhenInUseUsageDescription are showing up in the UI, how can we localise it?Rohde
I did both of these things and still no dice...user never gets prompted, even on a fresh install. I even went into settings and enabled location services manually for my app, and STILL do not get any location updates, and the auth status is always "not determined". I'm rather frustrated with Apple for screwing with this and breaking a lot of perfectly good code. But, such is life.Turnstone
Even more weirdness ensues...when I allow location services for my app manually in settings, on launch my auth status shows as "authorized". Then I immediately get a notification that it has changed to "not determined". Better yet, when I click back to settings, my change is undone! What the hell???Turnstone
D'oh! Figured it out...I was using quick-open to jump to the plist, and it was the plist for a framework I'm using rather than for the app itself. That was stupid.Turnstone
@OrtwinGentz, this solution worked for me with my deployment target set to 7.0. Without it, the 8.0 devices were failing to get location services. Is this what you mean? Has something changed since you first posted?Emulation
@Emulation my comment is obsolete now since iOS 8 is out. Before it was out, one could not use the requestAlwaysAuthorization selector because it was only available in the Beta SDK and builds against a Beta SDK aren't accepted in the App Store review.Rounds
It's 3:18 in the morning. Many thanks to @OrtwinGentz for my remaining couple hours of sleep!!Anthropomorphosis
Location monitoring is a very complexed subject when balance between battery consumption and 'always-on' accuracy is so important. Here's a great SDK that does it all for you: github.com/IngeoSDK/ingeo-ios-sdkPinckney
I had a legacy MyApp.plist that I was updating (from XCode 4 or something) and after many hours figured that I needed to select my target (of which I had 2) then Info -> Custom iOS Target Properties and add in the new strings there, once for each target. What a faff !Generative
For what it's worth, the key needs to go in the applications plist, even if the location manager code is in a framework.Boomkin
A
320

I was pulling my hair out with the same problem. Xcode gives you the error:

Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.

But even if you implement one of the above methods, it won't prompt the user unless there is an entry in the info.plist for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription.

Add the following lines to your info.plist where the string values represent the reason you you need to access the users location

<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>

I think these entries may have been missing since I started this project in Xcode 5. I'm guessing Xcode 6 might add default entries for these keys but have not confirmed.

You can find more information on these two Settings here

Adrieneadrienne answered 5/6, 2014 at 15:58 Comment(10)
xcode 6 does not add these keys by default, if you intend to implement CLLocationManager you must add them manuallyEmmanuel
At least one of those keys are required to use location in iOS 8.Selfconsistent
I also had to add these manually, could not add through the RawValues view of info.plist in Xcode6!Rockoon
i looked forever for this. My [CLLLocationManager authorizationStatus] message was only returning a value of <nil>. After adding the above keys it started returning the respective enumerations for the messages' output. From what ive found this is a known iOS 8 bug but couldnt find anything in my context for ages. Thanks a mil!Gabrielagabriele
I was able to add the keys in the Xcode 6 GM, though there's no long-string version. Works!Thereabouts
I like the string value you put inPittel
One question, how can I localized this message ?Selfmade
Stupid question: what is a good message here? And how to localize it?Knowland
The message will appear as the sub-message in the Alert that asks whether the user would like to share their location. As such, simply being empty (blank) seems to make the most sense in my application. An explanation of why you want to use location would also make sense. However, NSLocationWhenInUseUsageDescription did not behave as expected for me (ie. kept getting permission denied, even though the return value was correct). NSLocationAlwaysUsageDescription worked fine.Gantt
Apple you FAILED! Why not have it default to a generic message? Why not give some type of error when trying to use location manager without this plist key?Emasculate
Z
105

To ensure that this is backwards compatible with iOS 7, you should check whether the user is running iOS 8 or iOS 7. For example:

#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

//In ViewDidLoad
if(IS_OS_8_OR_LATER) {
   [self.locationManager requestAlwaysAuthorization];
}

[self.locationManager startUpdatingLocation];
Zolazoldi answered 27/6, 2014 at 1:14 Comment(8)
A better way than checking version is to check to see if the object has that selector, e.g.: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...Selfconsistent
I had trouble just implementing @progrmr's solution when building on Xcode 5, since it doesn't know what the requestAlwaysAuthorization method is. My additional solution was to use this line in the if statement instead of a normal method call: [self.locationManager performSelector:@selector(requestAlwaysAuthorization)];. Maybe this is obvious to other people, but it took me a while to figure out. I think it's the right solution until the final Xcode 6 is released.Intoxication
The right solution is to build with Xcode 6. If you are building with Xcode 5 you don't need to request authorization, it's automatic.Selfconsistent
You might have a point. My concern was that I wanted my code to compile in Xcode 5 (even though it won't work on iOS 8 unless compiled in Xcode 6) while my team transitions to Xcode 6. But maybe it's a better workflow to write the code normally and not merge it in until we move to Xcode 6.. Thanks.Intoxication
@Intoxication the recommended approach is to conditionally compile using the SDK defined macro __IPHONE_OS_VERSION_MAX_ALLOWED (#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)Mckinnon
Don't forget to set the delegate for the location manager and allocate it: _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; #24718047 has a the complete code if you're still stuckPyotr
for the life of me i cannot get this to work. It works great on iOS 8 (with the call for requestAlwaysAuthorization) but as soon as i put in the IF statement to check iOS version, it stops working on iOS8 and the prompt to allow to use location flashes and immediately disappears and I don't get my location. Anyone have any ideas why? its driving me insane!Iodate
You have to call '[self.locationManager startUpdatingLocation];' when the user have accepted / rejected the authorization. This is my code: - (void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) { [_locationManager startUpdatingLocation]; } }Prostration
C
51
- (void)startLocationManager
{
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone; //whenever we move
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingLocation];
    [locationManager requestWhenInUseAuthorization]; // Add This Line


}

And to your info.plist File enter image description here

Champignon answered 30/9, 2014 at 10:24 Comment(5)
Found similar solution in more descriptive way at datacalculation.blogspot.in/2014/11/…Amerind
@Hemang: According to the Apple Dev Documentation: It is safe to start location services before the authorization status of your app is determined. Although you can start location services, those services do not deliver any data until the authorization status changes to kCLAuthorizationStatusAuthorizedAlways or kCLAuthorizationStatusAuthorizedWhenInUse.Southerner
A bit late, but I recommend You hide irrelevant parts of Your plist file, especially FacebookAppIDDormer
Thanks But thats just a dummy sample :)Champignon
It's also important that the project is pointing to the right info.plist (the one where the key is defined). That's determined in the project build settings under Info.plist File.Pectase
B
30

According to the Apple docs:

As of iOS 8, the presence of a NSLocationWhenInUseUsageDescription or a NSLocationAlwaysUsageDescription key value in your app's Info.plist file is required. It's then also necessary to request permission from the user prior to registering for location updates, either by calling [self.myLocationManager requestWhenInUseAuthorization] or [self.myLocationManager requestAlwaysAuthorization] depending on your need. The string you entered into the Info.plist will then be displayed in the ensuing dialog.

If the user grants permission, it's business as usual. If they deny permission, then the delegate is not informed of location updates.

Baccate answered 8/6, 2014 at 22:16 Comment(1)
I found simple description here at datacalculation.blogspot.in/2014/11/…Amerind
U
28
- (void)viewDidLoad
{
    
    [super viewDidLoad];
    self.locationManager = [[CLLocationManager alloc] init];
    
    self.locationManager.delegate = self;
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
        NSUInteger code = [CLLocationManager authorizationStatus];
        if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
            // choose one request according to your business.
            if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
                [self.locationManager requestAlwaysAuthorization];
            } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
                [self.locationManager  requestWhenInUseAuthorization];
            } else {
                NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
            }
        }
    }
    [self.locationManager startUpdatingLocation];
}

>  #pragma mark - CLLocationManagerDelegate

    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
        NSLog(@"didFailWithError: %@", error);
        UIAlertView *errorAlert = [[UIAlertView alloc]
                                   initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [errorAlert show];
    }
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"didUpdateToLocation: %@", newLocation);
        CLLocation *currentLocation = newLocation;
        
        if (currentLocation != nil) {
            longitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
            latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
        }
    }

In iOS 8 you need to do two extra things to get location working: Add a key to your Info.plist and request authorization from the location manager asking it to start. There are two Info.plist keys for the new location authorization. One or both of these keys is required. If neither of the keys are there, you can call startUpdatingLocation but the location manager won’t actually start. It won’t send a failure message to the delegate either (since it never started, it can’t fail). It will also fail if you add one or both of the keys but forget to explicitly request authorization. So the first thing you need to do is to add one or both of the following keys to your Info.plist file:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Both of these keys take a string

which is a description of why you need location services. You can enter a string like “Location is required to find out where you are” which, as in iOS 7, can be localized in the InfoPlist.strings file.

enter image description here

Ulm answered 17/12, 2014 at 3:26 Comment(0)
S
19

My solution which can be compiled in Xcode 5:

#ifdef __IPHONE_8_0
    NSUInteger code = [CLLocationManager authorizationStatus];
    if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
        // choose one request according to your business.
        if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
            [self.locationManager requestAlwaysAuthorization];
        } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
            [self.locationManager  requestWhenInUseAuthorization];
        } else {
            NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
        }
    }
#endif
    [self.locationManager startUpdatingLocation];
Sarisarid answered 24/9, 2014 at 12:13 Comment(2)
Nice dynamic solution, to use in all apps. I would change the order though and instead of checking for iphone 8.0, I would check if location manager responds to authorization and then run the authorizationstatus to get the code. This will make it more universal.Downy
Worked on xCode 7.2 as well.Anaplasty
T
17

The old code for asking location won't work in iOS 8. You can try this method for location authorization:

- (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];
    }
}
Trichromat answered 27/9, 2014 at 9:54 Comment(2)
UIAlertView has been deprecated. You should use UIAlertController instead.Genipap
yeah I know its deprecated but this will also work. but yes better use UIAlertController for IOS8.Trichromat
H
13

In iOS 8 you need to do two extra things to get location working: Add a key to your Info.plist and request authorization from the location manager asking it to start

info.plist:

<key>NSLocationUsageDescription</key>
<string>I need location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I need location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>I need location</string>

Add this to your code

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}
Heterolecithal answered 2/10, 2014 at 6:40 Comment(4)
it's not clear if your pseudocode is a preprocessor call or a regular callMasoretic
Add this to your constants.h or .pch file: #define IS_OS_8_OR_LATER ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)Geanine
Why would you request both, you should add a comment mentioning only to use one or the other depending on your application needsPelkey
the info.plist part is easy enough to do in Unity3d, but how would I add the code part if using unity3d ? where ?Lagasse
R
11

One common error for Swift developers:

First make sure you add a value to the plist for either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription.

If you are still not seeing a window pop up asking for authorization, look to see if you are putting the line var locationManager = CLLocationManager() in your View Controller's viewDidLoad method. If you do, then even if you call locationManager.requestWhenInUseAuthorization(), nothing will show up. This is because after viewDidLoad executes, the locationManager variable is deallocated (cleared out).

The solution is to locate the line var locationManager = CLLocationManager() at the top of the class method.

Reasonable answered 17/2, 2015 at 22:40 Comment(0)
H
9

Before [locationManager startUpdatingLocation];, add an iOS8 location services request:

if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
    [locationManager requestAlwaysAuthorization];

Edit your app's Info.plist and add key NSLocationAlwaysUsageDescription with the string value that will be displayed to the user (for example, We do our best to preserve your battery life.)

If your app needs location services only while the app is open, replace:

requestAlwaysAuthorization with requestWhenInUseAuthorization and

NSLocationAlwaysUsageDescription with NSLocationWhenInUseUsageDescription.

Hemocyte answered 11/11, 2014 at 14:20 Comment(0)
G
9

I was working on an app that was upgraded to iOS 8 and location services stopped working. You'll probably get and error in the Debug area like so:

Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.

I did the least intrusive procedure. First add NSLocationAlwaysUsageDescription entry to your info.plist:

Enter image description here

Notice I didn't fill out the value for this key. This still works, and I'm not concerned because this is a in house app. Also, there is already a title asking to use location services, so I didn't want to do anything redundant.

Next I created a conditional for iOS 8:

if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
    [_locationManager requestAlwaysAuthorization];
}

After this the locationManager:didChangeAuthorizationStatus: method is call:

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:  (CLAuthorizationStatus)status
{
    [self gotoCurrenLocation];
}

And now everything works fine. As always, check out the documentation.

Gerianne answered 24/11, 2014 at 16:14 Comment(0)
L
7

Solution with backward compatibility:

SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
    [self.locationManager respondsToSelector:requestSelector]) {
    [self.locationManager performSelector:requestSelector withObject:NULL];
} else {
    [self.locationManager startUpdatingLocation];
}

Setup NSLocationWhenInUseUsageDescription key in your Info.plist

Larocca answered 11/9, 2014 at 5:22 Comment(2)
This is not correct, what about the case kCLAuthorizationStatusDenied? it jumps to else and starts updating the location which is not correct!Radmen
@BenMarten I don't think it should matter. You should be handling that yourself with locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error. He did, however, forget to add startUpdatingLocation to the if statement so after they accept or deny it, it doesn't actually call startUpdateLocation.Charente
L
6

Solution with backward compatibility which doesn't produce Xcode warnings:

SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
  [self.locationManager respondsToSelector:requestSelector]) {
((void (*)(id, SEL))[self.locationManager methodForSelector:requestSelector])(self.locationManager, requestSelector);
  [self.locationManager startUpdatingLocation];
} else {
  [self.locationManager startUpdatingLocation];
}

Setup NSLocationWhenInUseUsageDescription key in your Info.plist.

For iOS version 11.0+ : Setup NSLocationAlwaysAndWhenInUseUsageDescription key in your Info.plist. along with other 2 keys.

Lukey answered 11/9, 2014 at 9:30 Comment(3)
This is not correct, what about the case kCLAuthorizationStatusDenied? it jumps to else and starts updating the location which is not correct!Radmen
This is quite strange, this works fine for me not fine perfectly fine with both allow and not allowing.Even Jacob solution looks accurate but didn't work for me. Strange but worked!!!Mendelson
Calling [self.locationManager startUpdatingLocation] right after requestWhenInUseAuthorization has no pointCount
N
5

This is issue with ios 8 Add this to your code

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

and to info.plist:

 <key>NSLocationUsageDescription</key>
 <string>I need location</string>
 <key>NSLocationAlwaysUsageDescription</key>
 <string>I need location</string>
 <key>NSLocationWhenInUseUsageDescription</key>
 <string>I need location</string>
Noam answered 2/9, 2015 at 7:20 Comment(1)
NSLocationUsageDescription is not used on iOS8+Scape
C
4

To Access User Location in iOS 8 you will have to add,

NSLocationAlwaysUsageDescription in the Info.plist 

This will ask the user for the permission to get their current location.

Casebound answered 17/11, 2014 at 4:49 Comment(0)
C
4

Objective-C Procedure

Follow the below instructions:

For iOS 11

For iOS 11, have a look at this answer: iOS 11 location access

You need to add two Keys into plist and provide a message as in the below image:

 1. NSLocationAlwaysAndWhenInUseUsageDescription
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

Enter image description here

For iOS 10 and below:

NSLocationWhenInUseUsageDescription

Enter image description here

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
if([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [locationManager requestWhenInUseAuthorization];
} else {
    [locationManager startUpdatingLocation];
}

Delegate Methods

#pragma mark - Lolcation Update
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", error);
    UIAlertView *errorAlert = [[UIAlertView alloc]
                               initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [errorAlert show];
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        case kCLAuthorizationStatusRestricted:
        case kCLAuthorizationStatusDenied:
        {
            // Do some error handling
        }
            break;

        default: {
            [locationManager startUpdatingLocation];
        }
            break;
    }
}
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations lastObject];
    userLatitude =  [NSString stringWithFormat:@"%f", location.coordinate.latitude];
    userLongitude = [NSString stringWithFormat:@"%f", location.coordinate.longitude];
    [locationManager stopUpdatingLocation];
}

Swift Procedure

Follow the below instructions:

For iOS 11

For iOS 11 have a look at this answer: iOS 11 location access

You need to add two keys into plist and provide a message as in the below image:

 1. NSLocationAlwaysAndWhenInUseUsageDescription
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

Enter image description here

For iOS 10 and below:

Enter image description here

import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()

//MARK- Update Location
func updateMyLocation() {
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
    if locationManager.respondsToSelector(#selector(CLLocationManager.requestWhenInUseAuthorization)) {
       locationManager.requestWhenInUseAuthorization()
    }
    else {
        locationManager.startUpdatingLocation()
    }
}

Delegate Methods

//MARK: Location Update
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
    NSLog("Error to update location :%@", error)
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .NotDetermined: break
    case .Restricted: break
    case .Denied:
            NSLog("do some error handling")
        break
    default:
        locationManager.startUpdatingLocation()
    }
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
     let location = locations.last! as CLLocation
    var latitude = location.coordinate.latitude
    var longitude = location.coordinate.longitude
}
Christy answered 24/10, 2017 at 4:57 Comment(2)
Please make sure NSLocationAlwaysUsageDescription is also added otherwise you will get an error while uploading on the app store.Christy
Your message should also be informative otherwise apple will reject the app while reviwing process.Christy
D
3

For those using Xamarin, I had to add the key NSLocationWhenInUseUsageDescription to the info.plist manually since it was not available in the dropdowns in either Xamarin 5.5.3 Build 6 or XCode 6.1 - only NSLocationUsageDescription was in the list, and that caused the CLLocationManager to continue to fail silently.

Dichromate answered 21/11, 2014 at 16:51 Comment(0)
L
2

A little helper for all of you that have more than one Info.plist file...

find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Add NSLocationWhenInUseUsageDescription string' {} 

It will add the needed tag to all of the Info.plist files in the current directory (and subfolders).

Another is:

find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Set NSLocationWhenInUseUsageDescription $YOURDESCRIPTION' {} 

It will add your description to all files.

Leshalesher answered 7/10, 2014 at 8:18 Comment(0)
M
2
        // ** Don't forget to add NSLocationWhenInUseUsageDescription in MyApp-Info.plist and give it a string

        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
        if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
            [self.locationManager requestWhenInUseAuthorization];
        }
        [self.locationManager startUpdatingLocation];


    // Location Manager Delegate Methods    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    {
        NSLog(@"%@", [locations lastObject]);

}
Marius answered 18/11, 2014 at 13:50 Comment(0)
M
2

Keep Cocoa Keys information always at your fingertips for those updates, here is the link:

https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW26

Enjoy.

Mikiso answered 30/7, 2015 at 23:51 Comment(0)
H
2

I get a similar error in iOS 9 (working with Xcode 7 and Swift 2):

Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.

I was following a tutorial, but the tutor was using iOS 8 and Swift 1.2. There are some changes in Xcode 7 and Swift 2. I found this code and it works fine for me:

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

    // MARK: Properties
    @IBOutlet weak var mapView: MKMapView!

    let locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
        self.mapView.showsUserLocation = true

    }

    // MARK: - Location Delegate Methods

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations.last
        let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
        self.mapView.setRegion(region, animated: true)
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("Errors: " + error.localizedDescription)
    }
}

Finally, I put that in info.plist: Information Property List: NSLocationWhenInUseUsageDescription Value: App needs location servers for staff

Hazlett answered 29/12, 2015 at 17:19 Comment(0)
S
2

In order to access the user's location in iOS, you need to add two keys,

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

into the Info.plist file.

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Because I want to know where you are!</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Want to know where you are!</string>

See the below image.

Info.plist image

Sprage answered 17/6, 2017 at 3:35 Comment(0)
C
1
  1. Add key NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription (background GPS use) with string asking to use GPS on each info.plist from each target.

  2. Ask for permission by running:

    [self initLocationManager:locationManager];

Where initLocationManager is:

// asks for GPS authorization on iOS 8
-(void) initLocationManager:(CLLocationManager *) locationManager{

    locationManager = [[CLLocationManager alloc]init];

    if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
        [locationManager requestAlwaysAuthorization];
}

Remember that if the keys are not on each info.plist for each target the app will not ask the user. The if provides compatibility with iOS 7 and the respondsToSelector: method guarantees future compatibility rather than just solving the issue for iOS 7 and 8.

Chisolm answered 16/11, 2014 at 22:4 Comment(0)
E
0

The problem for me was that the class that was the CLLocationManagerDelegate was private, which prevented all the delegate methods from being called. Guess it's not a very common situation but thought I'd mention it in case t helps anyone.

Emarie answered 7/7, 2015 at 5:34 Comment(0)
P
0

I add those key in InfoPlist.strings in iOS 8.4, iPad mini 2. It works too. I don't set any key, like NSLocationWhenInUseUsageDescription, in my Info.plist.


InfoPlist.strings:

"NSLocationWhenInUseUsageDescription" = "I need GPS information....";

Base on this thread, it said, as in iOS 7, can be localized in the InfoPlist.strings. In my test, those keys can be configured directly in the file InfoPlist.strings.

So the first thing you need to do is to add one or both of the > following keys to your Info.plist file:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

Both of these keys take a string which is a description of why you need location services. You can enter a string like “Location is required to find out where you are” which, as in iOS 7, can be localized in the InfoPlist.strings file.


UPDATE:

I think @IOS's method is better. Add key to Info.plist with empty value and add localized strings to InfoPlist.strings.

Peppermint answered 30/7, 2015 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.