我的应用在iOS 7上可以正常运行,但在iOS 8 SDK上不起作用。
CLLocationManager
没有返回位置信息,而且我在设置 -> 定位服务下也看不到我的应用程序。我在Google上搜索了一下这个问题,但是没有找到任何东西。可能出了什么问题?
我的应用在iOS 7上可以正常运行,但在iOS 8 SDK上不起作用。
CLLocationManager
没有返回位置信息,而且我在设置 -> 定位服务下也看不到我的应用程序。我在Google上搜索了一下这个问题,但是没有找到任何东西。可能出了什么问题?
我最终解决了自己的问题。
显然在iOS 8 SDK中,需要调用CLLocationManager
的requestAlwaysAuthorization
(后台定位)或requestWhenInUseAuthorization
(仅前台定位)才能开始定位更新。
此外,还需要在Info.plist
中添加NSLocationAlwaysUsageDescription
或NSLocationWhenInUseUsageDescription
键以显示在提示中的消息。 添加这些内容解决了我的问题。
获取更多详细信息,请参见: iOS 8中核心位置管理器的更改
我曾经遇到同样的问题,Xcode会给你一个错误提示:
尝试在未提示用户授权的情况下启动
MapKit
位置更新。必须先调用-[CLLocationManagerrequestWhenInUseAuthorization]
或-[CLLocationManager requestAlwaysAuthorization]
。
但是即使您实现了上述方法之一,它也不会提示用户,除非在info.plist中有NSLocationAlwaysUsageDescription
或NSLocationWhenInUseUsageDescription
的条目。
请将以下行添加到您的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可能会为这些键添加默认条目,但尚未确认。
您可以在此处找到有关这两个设置的更多信息。
为了确保向后兼容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];
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
- progrmrrequestAlwaysAuthorization
方法是什么。我的附加解决方案是在'if'语句中使用这行代码,而不是正常的方法调用:[self.locationManager performSelector:@selector(requestAlwaysAuthorization)];
也许对其他人来说这很明显,但我花了一段时间才想出来。我认为这是正确的解决方案,直到最终的Xcode 6发布。 - VinceFior__IPHONE_OS_VERSION_MAX_ALLOWED
进行条件编译 (#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
)。 - Steven Kramer- (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文件中必须包含一个NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
键值。在注册位置更新之前,需要从用户那里请求权限,可以通过调用[self.myLocationManager requestWhenInUseAuthorization]
或[self.myLocationManager requestAlwaysAuthorization]
来实现,取决于您的需求。然后,在随后的对话框中将显示您输入到Info.plist中的字符串。
如果用户授权,则按照通常的方式运行。如果他们拒绝授权,则不会通知委托进行位置更新。
- (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文件中:
这两个键都需要一个字符串,该字符串描述了您需要位置服务的原因。您可以输入类似于“需要定位才能确定您的位置”这样的字符串,就像在iOS 7中一样,可以在InfoPlist.strings文件中本地化。
我在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];
旧的请求位置的代码在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];
}
}
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];
}
Swift开发者常见错误:
首先,请确保您为NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
之一的属性添加了一个值。
如果您仍然没有看到弹出窗口要求授权,请查看是否在您的视图控制器的viewDidLoad
方法中放置了var locationManager = CLLocationManager()
这一行代码。如果是这样,则即使您调用locationManager.requestWhenInUseAuthorization()
,也不会显示任何内容。这是因为在执行完viewDidLoad
后,locationManager变量被释放(清除)。
解决方案是将var locationManager = CLLocationManager()
代码行放置在类方法的顶部。