requestAlwaysAuthorization not showing permission alert
Asked Answered
D

17

37

I'm trying to use some fancy iBeacons without success, kCLAuthorizationStatusNotDetermined all time. According to other questions it's a requirement to add those keys to info.plist (some questions says one, other says both). According to an article for iBeacons I need the Always option.

<key>NSLocationWhenInUseUsageDescription</key>
<string>Nothing to say</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Permiso para acceder siempre</string>

At viewDidAppear:

self.locManager = [[CLLocationManager alloc]init];
self.locManager.delegate = self;
[self.locManager requestAlwaysAuthorization];
NSUUID* region1UUID = [[NSUUID alloc]initWithUUIDString:@""]; //ibeacon real UUID between "". Checked it's not nil.

self.beaconRegion = [[CLBeaconRegion alloc]
                                initWithProximityUUID:proximityUUID
                                identifier:@"myCoolString"];

self.beaconRegion.notifyEntryStateOnDisplay = YES;
self.beaconRegion.notifyOnEntry = YES;
self.beaconRegion.notifyOnExit = NO;
[self.locManager startMonitoringForRegion:self.beaconRegion];
[self.locManager startRangingBeaconsInRegion:self.beaconRegion];

Icon didn't appear at Settings/Privacy/Location until it was executed one of the two last methods. The Alert View to approve permissions never appears. If I perform a manual change at Location Settings and check it it will change status but at a few moments later Location at Settings will delete "Always" status for my app and will leave it blank again. Later I check with no luck

-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {

Any ideas what is missing or wrong? Thank you

Deb answered 23/9, 2014 at 21:37 Comment(6)
Check under privacy -> Location Services and make sure it isn't disabled for your app. Once it is explicitly disabled the user won't be prompted. Try deleting your app from the device and re-installing itCorneille
I've tried reinstalling several times. The process is when dialog doesn't appears in the app, I go to settings/privacy/location and check as "Always", after a few seconds it goes to full purple icon. Then I go to home, back to settings app and voilà, my app is still there but instead of "always" is blank againDeb
Sounds like something is messed up with your device. Do you have another device you can test on? Or the simulator?Corneille
I have tested it in my phone and ipad, and it's the same behaviour in both. Tried also this scenario: Device connected. Set "Always" option at settings, run the app and then it dissapears from settings.Deb
@Corneille I'm trying to find out if the documentation explains that the permission request is not shown if the location permission is explicitly not allowed for a given app or if this has changed since 2014Shush
For me? I was testing it on my iPhone 11 - iOS 15.5, did everything right. I just had to reset the iPhone's privacy and network settings.Yacketyyak
D
50

For iOS 11 developers, you should take a look at this post: Location Services not working in iOS 11.


TL;DR: you need ALL THREE location keys in the Info.plist:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>...</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>...</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>...</string>

Along with InfoPlist.strings translations in case of multilingual apps.

Dorchester answered 1/11, 2017 at 8:10 Comment(1)
You need to add these values to the root of Info.plist. The values are strings that will be presented to the user in an alert. See developer.apple.com/documentation/corelocation/….Dorchester
F
20

Had exactly the same problem. It turned out that in my case the NSLocationAlwaysUsageDescription was required in my InfoPlist.strings localization files as well. Having NSLocationAlwaysUsageDescription in Info.plist wasn't enough...

Fairlead answered 24/2, 2015 at 11:40 Comment(2)
I would add, also check if you have a Info-Debug.plist, etc. as I had put the string in my main Info.plist file but forgot to copy it over to the other. So in the simulator everything was silently failing much to my consternation.Belvia
where did you find such list (InfoPlist)? I can't find itHazelhazelnut
G
19

I have noticed that if your instance of CLLocationManager is destroyed before the alert shows, you will never see the alert. In my case I was creating a local variable of the location manager in the AppDelegate to ask for permission.

CLLocationManager *locationManager = [[CLLocationManager alloc] init];
if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
    [locationManager requestAlwaysAuthorization];
}

Changing the local variable to an instance variable made the alert to display:

@interface AppDelegate () {
    CLLocationManager *_locationManager;
}
@end

_locationManager = [[CLLocationManager alloc] init];
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
    [_locationManager requestAlwaysAuthorization];
}
Goeselt answered 19/6, 2015 at 8:23 Comment(1)
This was the problem for me also. Thanks!Sweetheart
F
14

I got a similar problem recently with IOS 11 when I tried to use

locationManager.requestAlwaysAuthorization()

The solution for me was to add all the 4 permissions in Info.plist to get the alert:

  • Privacy - Location When In Use Usage Description
  • Privacy - Location Usage Description
  • Privacy - Location Always Usage Description
  • Privacy - Location Always and When In Use Usage Description
Fulltime answered 11/8, 2018 at 18:14 Comment(0)
D
7

Just add this lines to your .plist file

<key>NSLocationAlwaysUsageDescription</key>
<string>Optional message</string>
Dexamyl answered 10/9, 2015 at 16:56 Comment(0)
I
3

Try to Start Updating Location (have helped for me)

[self.locationManager startUpdatingLocation];
Ionogen answered 24/9, 2014 at 10:59 Comment(0)
S
3

For ios 11 Its important to add below mention new permission which is

NSLocationAlwaysAndWhenInUseUsageDescription

along with the old permission which is

NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription

to fix the requestAlwaysAuthorization not showing permission alert.

Slipstream answered 22/8, 2019 at 18:50 Comment(0)
P
3

Hardware-dependent System Issue?

iOS 13.1.3, iPhone 7 (model ID "iPhone9,1")

Seems like system Settings->Privacy->Location in some way cache permissions even after app deletion (at least, during the same iOS session and for specified configuration).

If 'allow once' is pressed and user deletes and reinstalls and runs the app again, didChangeAuthorizationStatus(_:) sends initial status .denied. (And therefore, according to CLLocationManager logic it does not show prompt alert after requestAlwaysAuthorization()). This .denied status was the root of the evil in this case.

If user folds the app between initial didChangeAuthorizationStatus(:) and requestAlwaysAuthorization(), this causes next update of didChangeAuthorizationStatus(:) with status other than .denied and prompt alert will be shown.

iOS 13.1.3, iPhone 7 (model ID "iPhone9,3") - issue does not reproduce. (initial status received is .notDetermined)

iOS 13.1.2 iPhone 8 - all ok, same as above

Protocol answered 23/10, 2019 at 10:11 Comment(3)
Have you found a solution for this?Gallegos
No, used workaround with timer/timeout for this particular case.Protocol
Our testers are observing a similar issue. iOS 13.2.2, when they keep deleting and reinstalling from Test Flight on iPhone 7 and 8, they occasionally run into scenarios where the app gets initial permission as .denied but then if you go to Settings, it shows While in Use. Prompt for location is never showed in this scenario and once you restart the app, it gets permissions as while in use or whatever was selected in the previous install. Seems like schedules some background task or something and takes time to clear out permissions.Nagy
H
2

Make sure you add the keys to the correct Info.plist file. Don't forget there's one for your App and one for AppTest.

Hertahertberg answered 9/4, 2015 at 13:38 Comment(1)
this was my problem. Thanks! :PScouting
D
1

Found, documented at forums and tested it's an Objective-C iOS 8 related bug. Same code written in Swift just works. Working swift code, delegate is call.

Add Core Location framework to Project Settings / Targets / Capabilities / Background Modes set "Location Updates" and "Uses Bluetooth LE Accessories" Add key at Info.plist NSLocationAlwaysUsageDescription

import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate  {

var locManager: CLLocationManager?

override func viewDidLoad() {
    super.viewDidLoad()
    self.locManager = CLLocationManager();
    self.locManager!.delegate = self;
    if (!CLLocationManager.locationServicesEnabled()) {
        println("Location services are not enabled");
    }
    self.locManager!.requestAlwaysAuthorization();
    self.locManager!.pausesLocationUpdatesAutomatically = false;
    let uuidString = ""  // My ibeacon string there
    let beaconIdentifier = "myCompany"
    let beaconUUID:NSUUID = NSUUID(UUIDString: uuidString)
    let beaconRegion:CLBeaconRegion = CLBeaconRegion(proximityUUID: beaconUUID,
        identifier: beaconIdentifier)
    self.locManager!.startMonitoringForRegion(beaconRegion)
    self.locManager!.startRangingBeaconsInRegion(beaconRegion)
    self.locManager!.startUpdatingLocation()
}

Dialog appears OK

Deb answered 24/9, 2014 at 14:36 Comment(1)
Most of this is incorrect.Medicament
C
1

Swift 3.X Latest code easily usage

import CoreLocation

 public var locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()


        locationManager.delegate = self
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()

}



    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        let altitudeG = locations.last?.altitude
        let longitudeG = locations.last?.coordinate.longitude
        let latitudeG = locations.last?.coordinate.latitude

print("\(altitudeG) \(longitudeG) \(latitudeG)")

    }
Caucus answered 4/4, 2017 at 7:26 Comment(1)
Most of this is incorrect.Medicament
B
0

I copied this tutorial ...

http://willd.me/posts/getting-started-with-ibeacon-a-swift-tutorial

It didn't work out the box, although the fix was very simple, don't declare

let locationManager = CLLocationManager()

But move it into the class as variable

var locationManager = CLLocationManager()

And it works!!

Boarer answered 10/10, 2015 at 7:41 Comment(0)
W
0

It will show a prompt when the location permission for your app isn't set and once when 'in use' location permission for your app is set, subsequent calls do not show (and I don't think there is any API feedback that the call was swallowed).

From Apple docs:

Discussion When the current authorization status is notDetermined , this method runs asynchronously and prompts the user to grant permission to the app to use location services. The user prompt contains the text from the NSLocationAlwaysUsageDescription key in your app’s Info.plist file, and the presence of that key is required when calling this method. After the status is determined, the location manager delivers the results to the delegate’s locationManager(:didChangeAuthorization:) method. If the current authorization status is anything other than notDetermined, this method does nothing and does not call the locationManager(:didChangeAuthorization:) method, with one exception. If your app has never requested always authorization and its current authorization status is authorizedWhenInUse , you may call this method one time to try and change your app's authorization status to authorizedAlways .

Whippletree answered 13/9, 2017 at 19:24 Comment(0)
D
0

For me on iOS 13, I had to reset the Simulator to trigger the permission prompt again.

Drake answered 5/12, 2019 at 21:59 Comment(0)
G
0

To add to that: be sure you have added the array UIBackgroundModes to your .plist and inserted the "location" value.

Apple will not tell you it is missing and give you WhenInUse instead.

So in summary:

  • Tell the system about your background modes through .plist (Required background modes > App registers for location updates)
  • Tell the location manager you want to receive updates in the background (self.locationManager.allowsBackgroundLocationUpdates = YES;)
  • Ask for permission from the user from instance variable ([self.locationManager requestAlwaysAuthorization])
  • Provide valid texts for this request (info.plist contains: NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription)
Giffard answered 25/12, 2020 at 10:28 Comment(0)
C
0

To be able to call requestAlwaysAuthorization() from CLLocationManager, you must have those 3 plist keys first:

  • NSLocationAlwaysAndWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription
  • NSLocationWhenInUseUsageDescription

Then you must call the locationManagerDidChangeAuthorization(_) with the below flow. The idea is first call requestWhenInUseAuthorization() when the authorizationStatus is notDetermined then, when the delegate call authorizedWhenInUse, you must requestAlwaysAuthorization()

This order is important, otherwise requestAlwaysAuthorization() will never be called.

final class LocationService: NSObject, CLLocationManagerDelegate {

  let locationManager = CLLocationManager()

  override init() {
    super.init()
    locationManager.delegate = self
  }

  func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {

    switch locationManager.authorizationStatus {
    case .authorizedWhenInUse, .authorizedAlways:
      locationManager.desiredAccuracy = kCLLocationAccuracyBest
      locationManager.requestAlwaysAuthorization() // This is where to call `always`.
      locationManager.startUpdatingLocation()
    case .restricted, .denied:
      // Manage what happens when a user denied the authorization
      break
    case .notDetermined:
      locationManager.requestWhenInUseAuthorization()
    @unknown default: break
    }
  }
}
Cropper answered 28/4 at 15:30 Comment(2)
Why would you call requestAlwaysAuthorization() under the case .authorizedAlways? Why initially call requestWhenInUseAuthorization() if your goal is to call requestAlwaysAuthorization()? Just call requestAlwaysAuthorization() under .notDetermined.Medicament
.requestAlwaysAuthorization() is only invoked once by CoreLocation, so it is safe calling it in the.authorizedAlways case. Note that calling it within .notDetermined won’t work without first triggering .requestWhenInUseAuthorization(). We could separate the .authorizedAlways() case, and call .startUpdatingLocation() under it, the same behavior would apply in both declaration types.Cropper
D
-1

recently, IOS 13, * save result request permission after user reinstall app

Dustidustie answered 5/12, 2019 at 4:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.