提问



在iOS  7上运行良好的我的应用程序不适用于iOS  8 SDK。


CLLocationManager不会返回某个位置,我也不会在设置 - > 位置服务下看到我的应用。我在这个问题上进行了谷歌搜索,但没有任何结果。可能有什么不对?

最佳参考


我最终解决了自己的问题。


显然在iOS 8 SDK中,在开始位置更新之前需要requestAlwaysAuthorization(用于背景位置)或requestWhenInUseAuthorization(仅在前景时的位置)调用CLLocationManager


Info.plist中还需要NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription键,并在提示中显示消息。添加这些解决了我的问题。


[87]


希望它可以帮助别人。


编辑:有关更多信息,请查看:Core-Location-Manager-Changes-in-ios-8 [88]

其它参考1


我正在用同样的问题拉出我的头发。 Xcode为您提供错误:



  尝试在没有提示的情况下开始MapKit位置更新
  位置授权。必须先调用-[CLLocationManager requestWhenInUseAuthorization]-[CLLocationManager requestAlwaysAuthorization]



但即使你实现了上述方法之一,它也不会提示用户,除非在NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription的info.plist中有一个条目。


将以下行添加到info.plist,其中字符串值表示您需要访问用户位置的原因


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

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


我认为自从我在Xcode 5中开始这个项目以来,这些条目可能已经丢失。我猜测Xcode 6可能会为这些密钥添加默认条目但尚未确认。


您可以在此处找到有关这两个设置的更多信息[89]

其它参考2


为确保向后兼容iOS 7,您应检查用户是否运行iOS 8或iOS 7.例如:


#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];

其它参考3


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


}


以及您的info.plist文件


其它参考4


根据Apple文档:



  • https://developer.apple.com/documentation/corelocation/requesting_permission_to_use_location_services

  • https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization



从iOS 8开始,您的应用程序的Info.plist文件中存在NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription键值。然后还需要在注册之前请求用户的许可根据您的需要,通过调用[self.myLocationManager requestWhenInUseAuthorization][self.myLocationManager requestAlwaysAuthorization]进行位置更新。您输入Info.plist的字符串将显示在随后的对话框中。[90] [91]


如果用户授予权限,则照常营业。如果他们拒绝许可,则代理人不会被告知位置更新。

其它参考5


- (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];
        }
    }



  在iOS 8中,您需要做两件额外的事情才能使位置正常工作:添加
  Info.plist的一个键,并从该位置请求授权
  经理要求它开始。新的有两个Info.plist键
  位置授权。需要这些键中的一个或两个。如果
  这两个键都没有,你可以调用startUpdatingLocation但是
  位置管理员实际上不会启动。它不会发送失败
  消息给代表(因为它从未开始,它不能
  失败)。如果你添加一个或两个键但忘记它也会失败
  明确请求授权。所以你需要做的第一件事
  是将以下一个或两个键添加到Info.plist文件中:




  • NSLocationWhenInUseUsageDescription

  • NSLocationAlwaysUsageDescription



这两个键都需要一个字符串



  这是对您需要位置服务的原因的描述。您可以
  输入一个字符串,如需要位置才能找到你所在的位置
  这与iOS 7一样,可以在InfoPlist.strings文件中进行本地化。





其它参考6


我的解决方案可以在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];

其它参考7


询问位置的旧代码在iOS 8中无法运行。您可以尝试使用此方法进行位置授权:


- (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];
    }
}

其它参考8


在iOS 8中,您需要做两件额外的事情才能让位置正常工作:在Info.plist中添加一个密钥,并向位置管理员请求授权,要求它启动


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>


将此添加到您的代码中


if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

其它参考9


Swift开发人员的一个常见错误:


首先确保为NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription的plist添加值。


如果您仍然没有看到弹出要求授权的窗口,请查看您是否在视图控制器的viewDidLoad方法中放置var locationManager = CLLocationManager()行。如果您do,那么即使你调用locationManager.requestWhenInUseAuthorization(),也不会显示任何内容。这是因为在viewDidLoad执行之后,将取消分配(清除)locationManager变量。


解决方案是将行var locationManager = CLLocationManager()定位在类方法的顶部。

其它参考10


[locationManager startUpdatingLocation];之前,添加iOS8位置服务请求:


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


编辑您的应用程序Info.plist并添加键NSLocationAlwaysUsageDescription以及将显示给用户的字符串值(例如,We do our best to preserve your battery life.)


如果您的应用仅在应用开放时需要位置服务,请替换:


requestAlwaysAuthorizationrequestWhenInUseAuthorization


NSLocationAlwaysUsageDescription NSLocationWhenInUseUsageDescription

其它参考11


我正在开发一个已升级到iOS  8的应用程序,并且位置服务已停止运行。你可能会在调试区域得到错误,如下所示:


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


我做了最少侵入性的程序。首先将NSLocationAlwaysUsageDescription条目添加到info.plist:





请注意,我没有填写此密钥的值。这仍然有效,我并不担心,因为这是一个内部应用程序。此外,已经有一个标题要求使用位置服务,所以我不想做任何多余的事情。


接下来我为iOS 8创建了一个条件:


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


在此之后调用locationManager:didChangeAuthorizationStatus:方法:


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


现在一切正常。与往常一样,查看文档。[92]

其它参考12


向后兼容的解决方案:


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


在Info.plist中设置NSLocationWhenInUseUsageDescription键

其它参考13


具有向后兼容性的解决方案,不会产生Xcode警告:


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];
}


Info.plist中设置NSLocationWhenInUseUsageDescription键。


适用于iOS版本11.0 + :
Info.plist中设置NSLocationAlwaysAndWhenInUseUsageDescription键。以及其他2个键。

其它参考14


这是ios 8的问题
将其添加到您的代码中


if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}


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

其它参考15


要在iOS 8中访问用户位置,您必须添加,


NSLocationAlwaysUsageDescription in the Info.plist 


这将要求用户获得获取其当前位置的权限。

其它参考16


对于那些使用 Xamarin 的人,我必须手动将密钥 NSLocationWhenInUseUsageDescription 添加到info.plist,因为它在Xamarin 5.5.3的下拉列表中不可用Build 6或XCode 6.1 - 只有NSLocationUsageDescription在列表中,这导致CLLocationManager继续无声地失败。

其它参考17


        // ** 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]);

}

其它参考18


对于拥有多个Info.plist文件的所有人来说,这是一个小帮手......


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


它会将所需的标记添加到当前目录(和子文件夹)中的所有Info.plist文件中。


另一个是:


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


它会将您的描述添加到所有文件中。

其它参考19


保持 Cocoa Keys 信息始终触手可及,以获取这些更新,以下是链接:


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


请享用。

其它参考20


我在iOS9中遇到类似的错误(使用Xcode 7和Swift 2):
尝试在不提示位置授权的情况下启动MapKit位置更新。必须先调用 - [[CLLocationManager requestWhenInUseAuthorization]]或 - [[CLLocationManager requestAlwaysAuthorization]]。
我正在学习一个教程,但是导师使用的是iOS8和Swift 1.2。 Xcode 7和Swift 2有一些变化,我找到了这个代码,它对我来说很好(如果有人需要帮助):


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


最后,我把它放在info.plist中:
信息属性列表: NSLocationWhenInUseUsageDescription
价值:应用需要员工的位置服务器

其它参考21


为了访问iOS中的用户位置。您需要添加两个键


NSLocationWhenInUseUsageDescription


NSLocationAlwaysUsageDescription


进入Info.plist文件。


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


见下图。


[94]

其它参考22


Objective-C程序
请按照以下说明操作:


适用于iOS-11
对于iOS 11,请看一下这个答案:iOS 11位置访问


需要将两个密钥添加到plist中并提供如下图所示的消息:


 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription



适用于iOS-10及以下版本: [96]


NSLocationWhenInUseUsageDescription


[97]


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];
}


快速程序


请按照以下说明操作:


适用于iOS-11
对于iOS 11,请看一下这个答案:iOS 11位置访问


需要将两个密钥添加到plist中并提供如下图所示的消息:


 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription



适用于iOS-10及以下版本: [99]


[100]


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

}

其它参考23



  1. 添加键NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription(背景GPS使用),并在每个目标的每个info.plist上使用GPS。

  2. 通过运行请求许可:


    [[self initLocationManager:locationManager]];



其中initLocationManager是:


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

    locationManager = [**CLLocationManager alloc]init];

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


请记住,如果每个目标的每个info.plist上没有按键,则应用程序不会询问用户。 if提供与iOS 7的兼容性,respondsToSelector:方法保证了未来的兼容性,而不仅仅是解决iOS 7和8的问题。

其它参考24


对我来说问题是CLLocationManagerDelegate的类是私有的,它阻止了所有委托方法的调用。猜猜这不是一个非常普遍的情况,但我想如果t帮助任何人我都会提到它。

其它参考25


我在 iOS 8.4,iPad mini 2中的InfoPlist.strings中添加了这些键。它也可以。我没有在Info.plist中设置任何键,如NSLocationWhenInUseUsageDescription





InfoPlist.strings :


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





基于这个帖子,它说,as in iOS 7可以在InfoPlist.strings中进行本地化。在我的测试中,这些键可以直接在文件InfoPlist.strings中配置。[101]



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

  
  

      
  • NSLocationWhenInUseUsageDescription

  •   
  • NSLocationAlwaysUsageDescription

  •   

  
  这两个键都带有一个字符串,它描述了你的原因
  需要位置服务。您可以输入一个字符串,如Location is
  需要找出你的位置,如 iOS 7 ,可以
  本地化在InfoPlist.strings文件中。






更新:


我认为@IOS的方法更好。用空值添加Info.plist键并将本地化字符串添加到InfoPlist.strings