位置服务不适用于iOS 8
我在iOS 7上运行良好的应用程序不支持iOS 8 SDK。
CLLocationManager
不返回一个位置,我也没有看到我的应用程序在设置 – > 位置服务 。 我在这个问题上进行了Googlesearch,但没有出现。 什么可能是错的?
我最终解决了自己的问题。
显然,在iOS 8 SDK中,在启动位置更新之前,需要requestAlwaysAuthorization
(用于后台位置)或requestWhenInUseAuthorization
(仅在前台调用位置时)在CLLocationManager
上调用。
还需要在Info.plist
使用NSLocationAlwaysUsageDescription
或NSLocationWhenInUseUsageDescription
项,并在提示中显示一条消息。 添加这些解决了我的问题。
希望它可以帮助别人。
编辑:欲了解更多信息,请看: Core-Location-Manager-Changes-in-ios-8
我用同样的问题拉我的头发。 Xcode给你的错误:
尝试启动
MapKit
位置更新,而不提示位置授权。 必须首先调用-[CLLocationManager requestWhenInUseAuthorization]
或-[CLLocationManager requestAlwaysAuthorization]
。
但是,即使您实现了上述方法之一,也不会提示用户,除非在info.plist中有NSLocationAlwaysUsageDescription
或NSLocationWhenInUseUsageDescription
。
将以下行添加到您的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文件
根据苹果公司的文件:
- 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文件中存在NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
键值。 在注册位置更新之前,还需要通过调用[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添加一个值, NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
。
如果你仍然没有看到一个窗口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
和
NSLocationAlwaysUsageDescription
与NSLocationWhenInUseUsageDescription
。
我正在开发一个升级到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' {}
它会将您的描述添加到所有文件。
保持cocoa密钥信息始终在这些更新您的指尖,这里是链接:
请享用。
我在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>
看到下面的图像。
-
添加关键
NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
(背景GPS使用)与string要求使用每个目标的每个info.plist
上的GPS。 -
通过运行请求权限:
[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.strings
configuration。
因此,您需要做的第一件事就是将以下一个或两个键添加到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 }