18

I am having an issue when requesting location permissions from user when I use iOS11 my info.plist contains

<key>NSLocationWhenInUseUsageDescription</key>
<string>When in use permissions</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>always permissions</string>
<key>NSLocationAlwaysAndWhenInUsageDescription</key>
<string>Always and in usage permissions</string>

I have two maps one for customer and another for employees. For employees I need to know their location even if the app is not running or is backgrounded (they are able to turn it off when signing out) and request permission using

locationManager.requestAlwaysAuthorization()

For customer i only need locations while the app is in use and request the permission using

locationManager.requestWhenInUseAuthorization()

In iOS 11 this only requests permission when in usage and never the always on permission.

In iOS 10 it has the correct behaviour.

The behaviour I want is as follows: When they are a customer (not signed in) it only asks for when in use permission. If they sign in (employee) it request location even when not in use.

If anyone can shed some light on what I am missing / done wrong it would be much appreciated.

Something to note if i remove the permission NSLocationAlwaysUsageDescription iOS10 and iOS11 have the same issue of not requesting always permission.

A bit more clarification. I have implemented didChangeAuthorization delegate function and it gets called when a users allow the permission from alert from calling requestWhenInUseAuthorization() however when I call requestWhenInUseAuthorization() function on location manager the delegate method is not called it is like it's never receiving that call and no alert dialog is shown to the user.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ben Avery
  • 1,724
  • 1
  • 20
  • 33
  • are you testing in real device ? and ya did you put break point on locationupdate locationmanager delegates method – Himanshu Moradiya Sep 25 '17 at 06:01
  • Yea testing on two real devices iPhone 5 running iOS 10.3.3 and iPhone 6 running iOS 11. I have logs in location manager delegate functions didChangeAuthorization and didUpdateLocations. Locations is getting called (when in the foreground) and did change authorisation when I request when in usage permissions but not always on permissions. – Ben Avery Sep 25 '17 at 06:11
  • Have a look into this Answer- https://stackoverflow.com/a/46339284/3024579 – Alok Oct 23 '17 at 07:54

4 Answers4

12

I figured out the issue by creating a quick stand alone app that only asked for permissions, I was given an error log that stated the keys I was using were wrong.

I had NSLocationAlwaysAndWhenInUsageDescription instead of NSLocationAlwaysAndWhenInUseUsageDescription which is odd because from the docs it states that NSLocationAlwaysAndWhenInUsageDescription should be used. Switching to include the correct key fixed issue and now permissions works as expected for iOS 11 and 10.

Thanks for all the help.

Ben Avery
  • 1,724
  • 1
  • 20
  • 33
8

In your info.plist file add this:

<key>NSLocationUsageDescription</key>
<string></string>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>

Now in your swift file, don't forget to add delegate: CLLocationManagerDelegate

In your viewDiDLoad(), add this:

locationManager = CLLocationManager()

locationManager.delegate = self

locationManager.requestWhenInUseAuthorization()

locationManager.desiredAccuracy = kCLLocationAccuracyBest

locationManager.startUpdatingLocation()

locationManager.startMonitoringSignificantLocationChanges()

// Here you can check whether you have allowed the permission or not.

if CLLocationManager.locationServicesEnabled()
    {
        switch(CLLocationManager.authorizationStatus())
        {

        case .authorizedAlways, .authorizedWhenInUse:

            print("Authorize.")

            break

        case .notDetermined:

            print("Not determined.")

            break

        case .restricted:

            print("Restricted.")

            break

        case .denied:

            print("Denied.")
        }
    }
Akhil Nair
  • 434
  • 1
  • 6
  • 17
  • 3
    Unfortunately this is not the issue for iOS 11 it requires NSLocationAlwaysAndWhenInUsageDescription https://developer.apple.com/documentation/corelocation/choosing_the_authorization_level_for_location_services/request_always_authorization – Ben Avery Sep 25 '17 at 07:21
  • 2
    You don't need break in a Swift switch case Akhil – Cesare Feb 08 '18 at 15:47
  • @Cesare My background is in C# and Java. Thanks for pointing it out. LOL :) – Akhil Nair Feb 23 '18 at 13:20
1

For both cases, customers and employees, you first need to call locationManager.requestWhenInUseAuthorization()

Then, only if they are employees, add a call to locationManager.requestAlwaysAuthorization()

See https://developer.apple.com/documentation/corelocation/choosing_the_authorization_level_for_location_services/request_always_authorization

Overview To configure always authorization for location services, do the following: Add the NSLocationWhenInUseUsageDescription key and the NSLocationAlwaysAndWhenInUsageDescription key to your Info.plist file. (Xcode displays these keys as "Privacy - Location When In Use Usage Description" and "Privacy - Location Always and When In Use Usage Description" in the Info.plist editor.) If your app supports iOS 10 and earlier, add the NSLocationAlwaysUsageDescription key to your Info.plist file. (Xcode displays this key as "Privacy - Location Always Usage Description" in the Info.plist editor.) Create and configure your CLLocationManager object. Call the requestWhenInUseAuthorization() initially to enable your app's basic location support. Call the requestAlwaysAuthorization() method only when you use services that require that level of authorization.

Witterquick
  • 6,048
  • 3
  • 26
  • 50
  • I should make it a little more clear when the app is opened everyone is treated as a customer and it calls ```locationManager.requestWhenInUseAuthorization()``` once they login it then requests ```locationManager.requestAlwaysAuthorization()``` my understanding was that as long as i had made the when in use request at some point I should be able to make always tracking request at any later point. Is that correct or have i misunderstood? – Ben Avery Sep 25 '17 at 06:57
  • Yes, it is correct. Some silly questions - 1. Did you try to remove the app from your iPhone and reinstalling it again? if not, try to clean the project, delete the app and then reinstall it. 2. Check your system settings - the user can disable location services in the system settings, either for your app specifically or for all apps. – Witterquick Sep 25 '17 at 07:04
  • 1) I did try installing/uninstalling. 2) I checked my system settings and on iOS11 it doesn't have the always permissions there not sure if that helps any. Thanks for your help. – Ben Avery Sep 25 '17 at 07:16
  • @BenAvery, I believe you can call alwaysInUse even without calling whileInUseFirst. The distinction is that if you ask for whileInUse first, you can request an upgrade to alwaysInUse through the system prompts. However, if you request alwaysInUse first and the user doesn't accept, you lose any ability to request an upgrade through the system prompt. – JustinM Sep 25 '17 at 07:56
-1

** Latest Working code in Swift 5.1:**

Plist: Add the entry

<key>NSLocationWhenInUseUsageDescription</key>
  <string>Needs Location when in use</string>


import UIKit
import CoreLocation

class ViewController: UIViewController {
    var locationManager: CLLocationManager?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManager = CLLocationManager()
        
        //Make sure to set the delegate, to get the call back when the user taps Allow option
        locationManager?.delegate = self
    }
}

extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            print("not determined - hence ask for Permission")
            manager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            print("permission denied")
        case .authorizedAlways, .authorizedWhenInUse:
            print("Apple delegate gives the call back here once user taps Allow option, Make sure delegate is set to self")
        }
    }
}
Naishta
  • 11,885
  • 4
  • 72
  • 54