95

I just rebuilt my app with the iOS 11 SDK in an attempt to remove the blue banner that is now always appearing. I thought - "Brilliant, that worked", only to discover that location services are now not working at all.

The application used to work with iOS 10 - Has anybody heard anything?

swiftBoy
  • 35,607
  • 26
  • 136
  • 135
William George
  • 6,735
  • 3
  • 31
  • 39

8 Answers8

161

It would appear that apple have added yet another privacy feature. The user is now able to override our requestAlwaysAuthorization and downgrade it to requestWhenInUseAuthorization - Which means as a developer we now have to supply both descriptions in the Info.plist

I found that they have added a new key NSLocationAlwaysAndWhenInUseUsageDescription

/*
*      Either the NSLocationAlwaysAndWhenInUseUsageDescription key or both the
*      NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription
*      keys must be specified in your Info.plist; otherwise, this method will do
*      nothing, as your app will be assumed not to support Always authorization.
*/

However, upon using this new key - the location service still didn't work, upon further searching I found this gem mixed in with all the extra debugging information:

This app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain both NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUseUsageDescription keys with string values explaining to the user how the app uses this data

Which directly contradicts the the comment that I found in the updated CLLocationManager.h file. So I've created a radar.

Good news, if you follow the advice of the debugging console, IE. add both the new key NSLocationAlwaysAndWhenInUseUsageDescription and one of the old keys NSLocationWhenInUseUsageDescription, locations services will start to work again.

William George
  • 6,735
  • 3
  • 31
  • 39
  • 2
    I'm facing a very similar situation. Only I'm testing in iOS 10.2 and I have `NSLocationAlwaysUsageDescription` added to my Info.plist which is the permission I need. But I get the above message in the console saying I need to add `NSLocationWhenInUseUsageDescription` as well. – Isuru Aug 03 '17 at 03:55
  • 8
    Unfortunately the user now gets a dialogue with three answers, where the most likely to be hit because of user impatience to get started is the top choice: "Only While Using the App". Which will render apps that require always in use to be useless unless the user goes through all the hassle of changing the setting again afterwards. At least "Always Allow" should have been the top choice when this is what the app is asking for! – Hans Terje Bakke Sep 29 '17 at 11:46
  • 1
    I have added all three description keys and I still am not receiving location updates. I'm adding locationmanagerdelgate in viewwillAppear and removing the delegate in viewwilldisapper. If I go to setting and select the already selected Allow Always. I get the update only once and then no more. ANy idea how to fix this. Thanks in advance!! – LoveMeSomeFood Oct 02 '17 at 21:23
  • @Uma - are you calling `startUpdatingLocation` or `requestLocation`? – William George Oct 02 '17 at 23:13
  • @WilliamGeorge I'm using `startUpdatingLocation` – LoveMeSomeFood Oct 03 '17 at 02:51
  • I had all three keys included, but I was still getting the above debugging information. The solution for that was to change the order of the keys. AlwaysAndWhenInUse has to come first, then I have Always, then WhenInUse. – Andreas Zwettler Nov 15 '18 at 11:13
  • For me it Is working, but now App Store started the complain and asked why you may need the always usage in background mode!! And they rejected us! Any idea? – Saeid Aug 05 '19 at 09:06
  • Was it a `meta` rejection? Periodically, they'll ask what the purpose of the background location is. You can reply in the resolution centre and it usually gets approved if you've given a good enough reason. – William George Aug 06 '19 at 20:01
  • Hey, so is there any method to strict user to enable just "ALWAYS" option for any app. I am working on tracking app and want to enable "always" option when reusting for permision. Is this possible?? – Archana Sharma Jan 23 '20 at 10:59
  • If you have more than one Info.plist make sure it's in the app's and not the Test ones. I spent 2 hours on this to find out I was editing the wrong plist. I hope this comment saves people from pulling their hair out. :-) – fawsha1 Feb 26 '20 at 20:49
52

Just to add the steps on fixing this:

2 ways to do it:

A) The easy way: Select your Info.plist file, add the properties, note that they start with PRIVCY instead of LOCATION... therefore, the exact names of these variables starts with "Privacy - Location ... " etc, add each here, and describe how the user would be seeing this on the warning.

B) The hard / interesting / programatic way (I like this way more):

Right click on your Info.plist for your app, and then select "View source code", you should see it all in XML,

Follow the other ...... format, and add these properties as follows:

<key>NSLocationAlwaysUsageDescription</key>
<string>Program requires GPS to track cars and job orders</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Program requires GPS to track cars and job orders</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Program requires GPS to track cars and job orders</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app uses your Microphone to allow Voice over IP communication with the Program Admin system</string>

Save, and then right-click on the info.plist file, and then select Property list, this should view the file back into the default view.

EDIT:

Another member asked for code, here it is:

1) On your .H file, add:

@property (strong, nonatomic) CLLocationManager *LocationManager;

2) On your .M file add under ViewDidAppear() function:

_LocationManager = [[CLLocationManager alloc] init];
[_LocationManager setDelegate:self];
_LocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_LocationManager.pausesLocationUpdatesAutomatically = NO;
[_LocationManager requestAlwaysAuthorization];

_LocationManager.headingFilter = 5;
_LocationManager.distanceFilter = 0;

[_LocationManager startUpdatingLocation];
[_LocationManager startUpdatingHeading];

This what works fine for me, hopefully the code would work for you too.

Regards

Heider

Heider Sati
  • 2,476
  • 26
  • 28
  • 1
    I have added all three description keys and I still am not receiving location updates. I'm adding locationmanagerdelgate in `viewwillAppear ` and removing the delegate in `viewwilldisapper`. If I go to setting and select the already selected `Allow Always`. I get the update only once and then no more. ANy idea how to fix this. Thanks in advance!! – LoveMeSomeFood Oct 02 '17 at 21:18
  • I will add my code now to illustrate what's working for me: – Heider Sati Oct 04 '17 at 09:11
  • I have the same code as yours. But Still, I do not get location updates, unless I go to home and come back to app. This happens only in iOS 11. I still could not figure out why. – LoveMeSomeFood Oct 06 '17 at 23:22
  • Could you have a look at this thread? https://stackoverflow.com/questions/46616496/ios-11-location-update-not-received. Thank you! – LoveMeSomeFood Oct 07 '17 at 03:54
  • Hi Uma, One of our users reported the same issue on one of the devices, I am investigating this and will get back to you, I guess IOS11 is keeping us all extremely busy at the moment... I will have to find out and resolve this asap, please bear with me... thanks – Heider Sati Oct 07 '17 at 05:03
  • Thanks for the quick reply @Haider Sati. I'm seeing this in iPhone 7 Plus, if it helps you. – LoveMeSomeFood Oct 07 '17 at 05:06
  • Hi Uma, I will answer the other thread that you opened, I think I have found the problem. This has to do with the difference between UserLocation.coordinate and UserLocation.location.coordinate. – Heider Sati Oct 07 '17 at 20:36
  • **NSLocationAlwaysAndWhenInUseUsageDescription** is must here – swiftBoy Jun 06 '19 at 11:39
24

working under iOS11 i discovered, that Info.plist needs al least NSLocationAlwaysAndWhenInUseUsageDescription in Info.plist:

enter image description here

Strange enough when your app is multilingual the localized versions of your strings need all three keys mentioned in this post else requestAlwaysAuthorization() and locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) will fail silently.

Shot showing german translation as example:

enter image description here

Hope this saves you time when stumbling upon.

iDoc
  • 452
  • 3
  • 8
18

Working in Swift 4.0.3

   <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
   <string>Description</string>

   <key>NSLocationAlwaysUsageDescription</key>
   <string>Will you allow this app to always know your location?</string>

   <key>NSLocationWhenInUseUsageDescription</key>
   <string>Do you allow this app to know your current location?</string>  
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53
16

Follow these steps:

I ran into the same issue with an app that needed "Always Authorization", and resolved it by following these steps:

1. Add NSLocationWhenInUseUsageDescription key to Info.plist

2. Add NSLocationAlwaysAndWhenInUseUsageDescription to Info.plist

3. Add NSLocationAlwaysUsageDescription to Info.plist (to support < iOS 11)

4. Call requestWhenInUseAuthorization() BEFORE requestAlwaysAuthorization()

You cannot execute requestAlwaysAuthorization() before requestWhenInUseAuthorization(). You must escalate to that permission level. Once I made these changes, location updates started working properly again.

More details can be found here:

https://developer.apple.com/documentation/corelocation/choosing_the_authorization_level_for_location_services/requesting_always_authorization

mhit0
  • 196
  • 1
  • 6
8

Tested on iOS 12.2 with Swift 5

Step 1. you must add following privacy permissions in plist file

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Application requires user’s location for better user experience.</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>Application requires user’s location for better user experience.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Application requires user’s location for better user experience.</string>

Step 2. make sure you have following swift code to get current locations

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    // MARK: Variables declearations
    @IBOutlet weak var mapView: MKMapView!
    var locationManager: CLLocationManager!

    // MARK: View Controller life cycle methods
    override func viewDidLoad() {
        super.viewDidLoad()
        //TODO: Make user you must add following three privacy permissions in plist
        //NSLocationWhenInUseUsageDescription
        //NSLocationAlwaysAndWhenInUseUsageDescription
        //NSLocationAlwaysUsageDescription

        getCurrentLocation()
    }

    func getCurrentLocation()
    {
        if (CLLocationManager.locationServicesEnabled())
        {
            locationManager = CLLocationManager()
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()
        }
    }

    // MARK: Location Manager Delegate methods
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
    {
        let locationsObj = locations.last! as CLLocation
        print("Current location lat-long is = \(locationsObj.coordinate.latitude) \(locationsObj.coordinate.longitude)")
        showOnMap(location: locationsObj)
    }
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Get Location failed")
    }

    func showOnMap(location: CLLocation )
    {
        let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
        mapView.setRegion(region, animated: true)
    }
}
swiftBoy
  • 35,607
  • 26
  • 136
  • 135
7

Better safe than sorry .. In iOS 11 : Add the below and you are good.

<key>NSLocationWhenInUseUsageDescription</key>
<string>Description</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Description</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>Description</string>
Abhishek Bedi
  • 5,205
  • 2
  • 36
  • 62
3

Swift : 3 i have faced the same issue. i was totally screwed up finding the solution. here is how i fixed the issue.

step-1 : Project file > Capabilities > background modes > select Location Update

step-2 : Add NSLocationWhenInUseUsageDescription , NSLocationAlwaysAndWhenInUseUsageDescription keys to Info.plist

step-3 :

manager.pausesLocationUpdatesAutomatically = false
manager.allowsBackgroundLocationUpdates = true
Santosh Sahoo
  • 134
  • 1
  • 5
  • allowsBackgroundLocationUpdates definitely solved my problem, I can't believe it's not reported in other responses and forums. From Apple docs: "you use this property to enable and disable background updates programmatically. For example, you might set this property to true only after the user enables features in your app where background updates are needed." "The default value of this property is false." https://developer.apple.com/documentation/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates – Andrea Gorrieri Feb 26 '19 at 08:39