iOS:应用在安装应用时未征求用户许可。每次获取kCLAuthorizationStatusNotDetermined-Objective-C和Swift


71

我正在尝试在我的iOS应用中获取用户位置。首先,我在项目中包含了corelocation框架。然后在一个按钮上单击“我正在调用核心位置api”,如下所示。当我尝试将其安装在设备中时,核心位置从不询问用户权限。当我尝试单击按钮获取位置时,我将kCLAuthorizationStatusNotDetermined定义为authorisationStatus。请帮助我。我不知道发生了什么事。

- (IBAction)fetchLessAccurateLocation:(id)sender {
    [self.txtLocation setText:@""];

    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    locationManager.distanceFilter = 1000;

    if ([self shouldFetchUserLocation]) {
        [locationManager startUpdatingLocation];
    }
}

这是我的shouldFetchUserLocation方法:

-(BOOL)shouldFetchUserLocation{

    BOOL shouldFetchLocation= NO;

    if ([CLLocationManager locationServicesEnabled]) {
        switch ([CLLocationManager authorizationStatus]) {
            case kCLAuthorizationStatusAuthorized:
                shouldFetchLocation= YES;
                break;
            case kCLAuthorizationStatusDenied:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"App level settings has been denied" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;
            case kCLAuthorizationStatusNotDetermined:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The user is yet to provide the permission" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;
            case kCLAuthorizationStatusRestricted:
            {
                UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The app is recstricted from using location services." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alert show];
                alert= nil;
            }
                break;

            default:
                break;
        }
    }
    else{
        UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"Error" message:@"The location services seems to be disabled from the settings." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
        [alert show];
        alert= nil;
    }

    return shouldFetchLocation;
}

这是我的核心位置委托方法:

- (void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(NSArray *)locations __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0){

    NSLog(@"location fetched in delegate");

    CLLocation* location = [locations lastObject];
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];

    if (abs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
        NSLog(@"inside loop.... latitude %+.6f, longitude %+.6f\n",
              location.coordinate.latitude,
              location.coordinate.longitude);
    }
    NSLog(@"latitude %+.6f, longitude %+.6f\n",
          location.coordinate.latitude,
          location.coordinate.longitude);
    [self.txtLocation setText:[NSString stringWithFormat:@"\nlatitude: %+.6f \nlongitude:   %+.6f", location.coordinate.latitude, location.coordinate.longitude]];

    [locationManager stopUpdatingLocation];
    [locationManager stopMonitoringSignificantLocationChanges];

    if(locationManager!=nil){
        locationManager.delegate= nil;
        locationManager= nil;
    }
}

2
我在iOS8 Beta中遇到了这个问题。以下答案无效。它包围了我几天,直到我发现以下内容:[iOS 8:位置服务无法正常工作] stackoverflow.com/a/24063578/1343200
uspython 2014年

1
此链接对我有帮助,我跳过了“在info.plist中添加'NSLocationAlwaysUsageDescription'”步骤。希望对您
有所

就我而言,我知道该怎么做,但是忘记将键/值放在info.plist中,谢谢。
IgniteCoders '16

Answers:


41

我遇到了同样的问题,重新安装我的应用后,kCLAuthorizationStatusNotDetermined无论何时检查[CLLocationManager authorizationStatus]并且该应用程序甚至没有出现在“设置”>“隐私”>“位置服务”中。

触发iOS提示用户批准访问位置服务的授权对话框,在[locationManager startUpdatingLocation]这种情况下,永远不会调用该对话框(您shouldFetchUserLocation将始终NO)。

Miguel C.的解决方案似乎是一个不错的解决方案,请尝试一下。

编辑iOS8.x

iOS8发布时,它使用CLLocationManager的方式几乎没有改变。如其他答案中几次提到的,与iOS7相比,它需要采取其他步骤。今天,我自己面对了这个问题,并找到了这篇文章(其他多个问题都引用了该文章,但它完成了我之前的回答)。希望能帮助到你!


您编辑中的链接。那帮助了我。苹果公司的愚蠢变化。给予更多控制是很好的,但是在没有任何警告的情况下破坏了很多代码和教程。
ecth 2015年

我只想添加此内容作为预防措施(以及以后的注意事项):在编辑plist时,可能需要以下键。而且它们不是默认键之一,因此它不会显示在提示中,更重要的是,记住在编辑plist时切换到Raw值。NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription
iamdavidlam 2015年

链接有很棒的解释。+1。
希玛

101

iOS8通过LocationsServices对我们进行了重大的API更改

假设 [CLLocationManager locationServicesEnabled]返回YES,

首次启动iOS应用程序[iOS7和iOS8]-locationMangers(CLLocationManager)authorizationStatus预设为

authorizationStatus(CLAuthorizationStatus) = kCLAuthorizationStatusNotDetermined

在iOS7 +中提示

初始化locationManger(CLLocationManager,Strong)并设置委托(CLLocationManagerDelegate)

现在,要提示用户使用位置服务,并在“设置”>“隐私”>“位置服务”下列出其应用,必须调用任何“位置服务方法”,这取决于应用程序的要求-例如,如果应用程序属于以下其中一种

位置更新- [self.locationManager startUpdatingLocation]

区域监控- [self.locationManager startMonitoringForRegion:beaconRegion]

在执行上述方法之后,iOS会立即提示用户请求接受应用程序中的位置服务,并且无论用户选择何种应用程序,都会在“设置”>“隐私”>“位置服务”下列出。

在iOS8 +中提示

与iOS8相同的情况是,首次启动App Locations Services

authorizationStatus(CLAuthorizationStatus) = kCLAuthorizationStatusNotDetermined

iOS 8,我们有了向用户显示提示的新方法

[self.locationManager requestAlwaysAuthorization] 
or
[self.locationManager requestWhenInUseAuthorization]

从iOS8开始可以使用requestAlwaysAuthorization / requestWhenInUseAuthorization。如果应用程序的部署目标是iOS7,则将其包装在if块下,以确保在iOS7中不会导致应用程序崩溃。

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

要么

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

很重要 ###:

根据iOS8,其强制性内容包括说明应用程序为何使用requestAlwaysAuthorization / requestWhenInUseAuthorization的字符串的信息。

对于kCLAuthorizationStatusAuthorized始终包含键/值(字符串值)对

NSLocationAlwaysUsageDescription = App use Locations service mode Always

对于kCLAuthorizationStatusAuthorizedWhenInUse包含键/值(字符串值)对

NSLocationWhenInUseUsageDescription = App use Locations service mode In Use 

info.plist的屏幕截图(如果有人对此感到困惑) 在此处输入图片说明


15
上面的“非常重要”部分非常重要。非常感谢您的提示!
cire.boroguies 2014年

1
@kraftydevil-iOS7 / iOS8表示目标设备的操作系统版本。其更好您按照此职位为更好地了解基地SDK /部署目标的stackoverflow.com/questions/18568572/...
Rithesh饶

1
@Tzoiker,如果您需要帮助,您需要详细说明自己-没有人可以因为“只是行不通”而为您提供帮助
Rithesh Rao 2015年

1
编辑以添加info.plist的屏幕截图。字符串“正在使用的应用程序使用位置服务”将出现在提示对话框中。您可以根据需要自定义此文本。
GeneCode 2015年

1
感谢@Rocotilos,对于我们所有的兄弟会,现在的答案都必须非常清楚。
Rithesh Rao 2015年

29

Objective-C请 遵循以下指示:

iOS-11 对于iOS 11,请查看以下答案:iOS 11位置访问

需要在plist中添加两个键,并提供如下图所示的消息:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription

在此处输入图片说明 iOS-10及以下版本:

NSLocationWhenInUseUsageDescription

在此处输入图片说明

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

委托方法

#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代码

请遵循以下指示:

iOS-11 对于iOS 11,请查看以下答案:iOS 11位置访问

需要在plist中添加两个键,并提供如下图所示的消息:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription

在此处输入图片说明 iOS-10及以下版本:

在此处输入图片说明

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()
    }
}

委托方法

//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

}

我只是在看WWDC,他说ios 11之前需要NSLocationAlwaysUsageDescription,而不是如您所述的WhenInUse-iOS 11必须具有WhenInUse和可选的AlwaysAndWhenInUse(您正确地声明了)
Ryan

@Rayan以前,开发人员可以选择从Always或While中选择,但是从iOS 11中,我们必须同时显示选项,并且用户可以从Always或While中进行选择。
阿洛克

@Alok我们如何可以删除,同时使用的应用程序。当我们选择它出现在IOS 11蓝条
拉胡尔·维亚斯

迅速4: - locationManager.responds(到:#selector(CLLocationManager.requestWhenInUseAuthorization))
Žღķ

17

您必须已NSLocationWhenInUseUsageDescription添加到info.plist。有点奇怪,但是只需将其添加为没有文本的字符串值,然后在您要位置开始时添加:

CLLocationManager * locationManager = [[CLLocationManager alloc] init];

[locationManager requestWhenInUseAuthorization];

是的 这是在iOS 8上引入的。它将起作用。但我的问题是发布的iOS 8.前长后
Rashmi兰詹mallick

确切地说,键= NSLocationWhenInUseUsageDescription,类型=字符串,值=(留空)
Brenwell

3
为什么是空字符串?您应该/可以使用它来为用户定制选项。这就是我们多年来一直在等待的...
朱利安·F·韦纳特

@Julian,它一直存在于iOS 6中,并被称为Privacy - Location Usage Description
Sergey Grischyov 2014年

@SergiusGee哦,我撤销了我的发言,对此表示抱歉;)
朱利安·F·韦纳特

12

如果您在iOS8上遇到此问题,请使用:requestWhenInUseAuthorization。


还有其他窍门吗?我的应用仍然无法在启动时请求授权... :(
Marcel

7
iOS 8需要以下条件... 1.将NSLocationAlwaysUsageDescription或NSLocationWhenInInUseUsageDescription添加到info.plist并使用requestWhenInUseAuthorization。
Abhilash Gopal 2014年

6

在iOS 8中,您需要执行两项额外的操作来使位置正常工作:向Info.plist添加一个密钥,并向位置管理器请求授权以要求其启动。有两个用于新位置授权的Info.plist键。这些密钥之一或全部是必需的。如果两个键都不存在,则可以调用startUpdatingLocation,但是位置管理器实际上不会启动。它也不会向代理发送失败消息(因为它从未启动,所以不会失败)。如果您添加一个或两个密钥,但是忘记显式地请求授权,它也会失败。

因此,您需要做的第一件事是向Info.plist文件添加以下一个或两个以下键:

NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription

这两个键都带有一个字符串,该字符串描述了为什么需要定位服务。您可以输入一个字符串,例如“需要位置才能找到自己的位置”,就像在iOS 7中一样,可以在InfoPlist.strings文件中进行本地化。

接下来,您需要为相应的定位方法whenInUse或Background请求授权。使用以下调用之一:

[self.locationManager requestWhenInUseAuthorization]
[self.locationManager requestAlwaysAuthorization]

有关更多信息


如果使用Unity3d,我将如何做第二部分?我终于在第1部分中获得了定位服务的工作,但是如何请求Auth?请问该代码在哪里?
CthulhuJon 2015年

3

自iOS 7发行以来,Rashmi Ranjan mallick在评论中几次提到了这个问题。我真的认为这是iOS 7的一个错误,在新版本的iOS中有很多错误。

对我来说,问题是相同的:

1.打开应用程序,从不询问位置。iOS并没有询问许可证
2.我去了Settings-> Privacy-> Location services,我的应用不在那儿。
3.我无法以任何方式更改应用的位置权限。

一种解决方法是:

1,杀死你的应用
2.使用总开关按钮禁用所有位置服务。
3.再次转到您的应用。
4,杀死你的应用
5.再次在上一个开关按钮上启用定位服务。
6.如果列表中仍未出现,请再次转到您的应用,再次将其杀死,然后返回设置。
7.现在它应该在那里。

这对我有用,我希望这是有用的。

更新:如果iOS 8确保您正在致电requestWhenInUseAuthorizationrequestAlwaysAuthorization

您可以遵循以下代码::)

#ifdef __IPHONE_8_0
    if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)
    {
        if([[Wave_SettingsObject sharedObject] backgroundLocationEnabled].boolValue == YES)
        {
            if(![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
            {
                NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription key");
            }

            if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) //iOS 8+
            {
                [locationManager requestAlwaysAuthorization];
            }
        }
        else if([[Wave_SettingsObject sharedObject] isLocationEnabled].boolValue == YES)
        {
            if(![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"])
            {
                NSLog(@"Info.plist does not contain NSLocationWhenInUseUsageDescription key");
            }

            if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) //iOS 8+
            {
                [locationManager requestWhenInUseAuthorization];
            }

        }
    }
#endif

2

卸载该应用程序,然后尝试再次运行。

如果不起作用,请转到设置并禁用对该应用程序的授权。之后,再次运行它以查看是否询问权限。

要么:

您可以使用以下代码强制应用开始监视位置:

self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];

在委托方法中,您可以检测获取位置是否有错误,并可以通知用户。

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    // Delegate of the location manager, when you have an error
    NSLog(@"didFailWithError: %@", error);

    UIAlertView *errorAlert = [[UIAlertView alloc]     initWithTitle:NSLocalizedString(@"application_name", nil) message:NSLocalizedString(@"location_error", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil];

    [errorAlert show];
}

如果您有任何问题,请告诉我。


1
我的问题是该应用程序未在设置中的位置服务下列出。
Rashmi Ranjan mallick

@RashmiRanjanmallick嗡嗡声这是有线的..即使卸载并重新安装也没有解决问题?
Miguel Chaves 2013年

1

尝试添加

[locationManager startUpdatingLocation]

还要确保打开了位置服务。

编辑:

另外,请尝试删除该应用程序并重新安装。可能存在该应用正在读取的记录,从而阻止了该应用请求使用位置的许可。


定位服务已打开。并且我还添加了[locationManager startUpdatingLocation]。但是,我是从按钮单击事件中调用的。
Rashmi Ranjan mallick

请尝试在viewDidLoad中进行设置,以便它有时间加载并检查设置。
Bot 2013年

实际上,我现在没有ios设备。因此也无法对此进行测试。但是您确定这会起作用吗?
Rashmi Ranjan mallick

另外,建议在实际需要位置数据之前就获取位置数据。它可能会影响设备的电池寿命。
Rashmi Ranjan mallick

1

提示您输入位置时,请不要忘记这些内容(iOS 8+):

  1. 在应用程序的info.plist上添加此标志:NSLocationAlwaysUsageDescription或NSLocationWhenInUseUsageDescription取决于您是否要始终访问位置或仅在使用应用程序时使用(如果您不需要始终访问,则建议使用第二个)。这是最重要的,因为它是新奇的。
  2. 如果您始终请求许可,请不要忘记在目标功能上添加位置更新作为后台模式
  3. 初始化位置管理器时,请确保您请求正确的权限:

    -(void)initLocationManager{
        locationManager = [[CLLocationManager alloc] init];
        locationManager.delegate=self;
    
        [locationManager requestAlwaysAuthorization]; // HERE ASK FOR THE RELEVANT
    }
    

为了在模拟器中进行测试,建议您从其选项中“重置所有内容和设置”。这是获得应用程序新用户完全相同的体验的唯一方法。


1

我遇到了这个问题,实现了所有必要的东西,包括pList键,而我的应用程序仍未请求位置。

原来的问题是locationManager变量不能是本地变量-它必须是实例变量。

所以代替

-(void) updateLocation {
   CLLocationManager *locationManager = ...
}

它必须是:

CLLocationManager *locationManager;

-(void) updateLocation {
  self.locationManager = ...
}

这是显而易见的。因为,如果您在本地声明它,则一旦超出范围,您将丢失该引用。
Rashmi Ranjan mallick 2015年

1

我有类似的问题,但原因不同。在这里添加它以防其他人使用。

我停止收到询问授权消息,并且由于该消息在其他答案中描述的要求尚未满足之前就已经起作用:plist中的密钥,检查授权状态,然后在ios8 +中请求许可。

就我而言,该问题与“访问指南”模式有关。这是一个用于信息亭的应用程序,并且只有在激活“访问指南”后,它才会开始定位信标。但是,在这种模式下,似乎没有发送要求授权消息。我可以通过将请求授权过程移动到第一个显示的视图的DidLoad来修复它。

使用相机的请求也会发生同样的事情。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.