位置服务不适用于iOS 8

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

CLLocationManager不返回一个位置,我也没有看到我的应用程序在设置 – > 位置服务 。 我在这个问题上进行了Googlesearch,但没有出现。 什么可能是错的?

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

显然,在iOS 8 SDK中,在启动位置更新之前,需要requestAlwaysAuthorization (用于后台位置)或requestWhenInUseAuthorization (仅在前台调用位置时)在CLLocationManager上调用。

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

在这里输入图像描述

希望它可以帮助别人。

编辑:欲了解更多信息,请看: Core-Location-Manager-Changes-in-ios-8

我用同样的问题拉我的头发。 Xcode给你的错误:

尝试启动MapKit位置更新,而不提示位置授权。 必须首先调用-[CLLocationManager requestWhenInUseAuthorization]-[CLLocationManager requestAlwaysAuthorization]

但是,即使您实现了上述方法之一,也不会提示用户,除非在info.plist中有NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

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

 <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可能会添加这些键的默认条目,但尚未确认。

你可以在这里find关于这两个设置的更多信息

为了确保这与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]; 
 - (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文件 在这里输入图像描述

根据苹果公司的文件:

从iOS 8开始,需要在应用的Info.plist文件中存在NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription键值。 在注册位置更新之前,还需要通过调用[self.myLocationManager requestWhenInUseAuthorization][self.myLocationManager requestAlwaysAuthorization]根据需要请求用户的许可。 您input到Info.plist中的string将显示在随后的对话框中。

如果用户同意,则照常营业。 如果他们拒绝了权限,那么代理不会被通知位置更新。

 - (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添加一个密钥,并请求位置pipe理器授权它开始。 有两个Info.plist密钥用于新的位置授权。 其中一个或两个键是必需的。 如果这两个键都不存在,则可以调用startUpdatingLocation,但位置pipe理器不会实际启动。 它不会发送失败消息给委托(因为它从来没有启动,它不能失败)。 如果您添加一个或两个密钥,但忘记明确请求授权,它也将失败。 所以你需要做的第一件事就是将下面的一个或两个键添加到Info.plist文件中:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

这两个键都是一个string

这是为什么你需要位置服务的描述。 您可以input一个string,如“需要find您所在的位置”,如iOS 7中,可以在InfoPlist.strings文件中进行本地化。

在这里输入图像描述

我可以在Xcode 5中编译的解决scheme:

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

请求位置的旧代码在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]; } } 

将此添加到您的代码中

 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> 

Swift开发人员常见的错误是:

首先确保你为plist添加一个值, NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription

如果你仍然没有看到一个窗口popup要求授权,看看你是否在您的视图控制器的viewDidLoad方法中放置var locationManager = CLLocationManager()行。 如果你这样做,那么即使你调用locationManager.requestWhenInUseAuthorization() ,也不会显示出来。 这是因为在viewDidLoad执行之后,locationManagervariables被释放(清除)。

解决scheme是在类方法的顶部findline var locationManager = CLLocationManager()

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

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

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

如果您的应用仅在应用打开时需要位置服务,请replace:

requestWhenInUseAuthorization

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

我正在开发一个升级到iOS 8的应用程序,位置服务停止工作。 你可能会得到和debugging区域中的错误,如下所示:

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

我做了最不干扰的程序。 首先添加NSLocationAlwaysUsageDescription条目到您的info.plist:

在这里输入图像说明

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

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

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

在这之后的locationManager:didChangeAuthorizationStatus:方法是调用:

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

现在一切正常。 一如既往,请查看文档 。

向后兼容的解决scheme:

 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项

向后兼容的解决scheme,不会产生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 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> 

要访问iOS 8中的用户位置,您将不得不添加,

 NSLocationAlwaysUsageDescription in the Info.plist 

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

对于那些使用Xamarin的人 ,我不得不手动添加关键NSLocationWhenInUseUsageDescription到info.plist,因为它在Xamarin 5.5.3 Build 6或XCode 6.1的下拉菜单中都不可用 – 只有NSLocationUsageDescription出现在列表中,导致CLLocationManager继续默默地失败。

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

对于所有拥有多个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' {} 

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

我在iOS9(使用Xcode 7和Swift 2)中遇到类似的错误: 尝试启动MapKit位置更新,而不提示位置授权。 必须首先调用 – [CLLocationManager requestWhenInUseAuthorization]或 – [CLLocationManager requestAlwaysAuthorization]。 我正在学习一个教程,但导师正在使用iOS8和Swift1.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值: 应用程序需要位置服务器的工作人员

为了访问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> 

看到下面的图像。

Info.plist图片

  1. 添加关键NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription (背景GPS使用)与string要求使用每个目标的每个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的问题。

我的问题是CLLocationManagerDelegate类是私人的,这阻止了所有的委托方法被调用。 猜猜这不是一个非常常见的情况,但是我认为我会提到它,以免有人帮助。

我将这些密钥添加到iOS 8.4,iPad mini 2的 InfoPlist.strings中。 我不在Info.plist设置任何键,比如NSLocationWhenInUseUsageDescription


InfoPlist.strings

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

基于这个线程 ,它说, as in iOS 7 ,可以在InfoPlist.strings中进行本地化。 在我的testing中,这些键可以直接在文件InfoPlist.stringsconfiguration。

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

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

这两个键都需要一个string,这是描述为什么你需要位置服务。 您可以input一个string,如“需要find您所在的位置”,如iOS 7中 ,可以在InfoPlist.strings文件中进行本地化。


更新:

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

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

Delegate Methods

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