objective-c 定位服务在 iOS 8 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24062509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Location Services not working in iOS 8
提问by ?zg
My app that worked fine on iOS 7 doesn't work with the iOS 8 SDK.
我在 iOS 7 上运行良好的应用程序不适用于 iOS 8 SDK。
CLLocationManagerdoesn't return a location, and I don't see my app under Settings-> Location Serviceseither. I did a Google search on the issue, but nothing came up. What could be wrong?
CLLocationManager不返回位置,我也没有在“设置”->“位置服务”下看到我的应用程序。我对这个问题进行了谷歌搜索,但没有任何结果。可能有什么问题?
回答by ?zg
I ended up solving my own problem.
我最终解决了我自己的问题。
Apparently in iOS 8 SDK, requestAlwaysAuthorization(for background location) or requestWhenInUseAuthorization(location only when foreground) call on CLLocationManageris needed before starting location updates.
显然在 iOS 8 SDK 中,requestAlwaysAuthorization(用于后台位置)或requestWhenInUseAuthorization(仅在前台时定位)CLLocationManager在开始位置更新之前需要调用。
There also needs to be NSLocationAlwaysUsageDescriptionor NSLocationWhenInUseUsageDescriptionkey in Info.plistwith a message to be displayed in the prompt. Adding these solved my problem.
还需要输入NSLocationAlwaysUsageDescription或NSLocationWhenInUseUsageDescription键入Info.plist要在提示中显示的消息。添加这些解决了我的问题。
Hope it helps someone else.
希望它可以帮助别人。
EDIT: For more extensive information, have a look at: Core-Location-Manager-Changes-in-ios-8
编辑:有关更广泛的信息,请查看:Core-Location-Manager-Changes-in-ios-8
回答by Henry
I was pulling my hair out with the same problem. Xcode gives you the error:
我正在用同样的问题拉我的头发。Xcode 给你错误:
Trying to start
MapKitlocation updates without prompting for location authorization. Must call-[CLLocationManager requestWhenInUseAuthorization]or-[CLLocationManager requestAlwaysAuthorization]first.
尝试在
MapKit不提示位置授权的情况下开始位置更新。必须打电话-[CLLocationManager requestWhenInUseAuthorization]或-[CLLocationManager requestAlwaysAuthorization]先。
But even if you implement one of the above methods, it won't prompt the user unless there is an entry in the info.plist for NSLocationAlwaysUsageDescriptionor NSLocationWhenInUseUsageDescription.
但即使你实现了上述方法之一,它也不会提示用户,除非 info.plist 中有一个条目NSLocationAlwaysUsageDescriptionor NSLocationWhenInUseUsageDescription。
Add the following lines to your info.plist where the string values represent the reason you you need to access the users location
将以下行添加到您的 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>
I think these entries may have been missing since I started this project in Xcode 5. I'm guessing Xcode 6 might add default entries for these keys but have not confirmed.
我认为自从我在 Xcode 5 中开始这个项目以来,这些条目可能已经丢失了。我猜 Xcode 6 可能会为这些键添加默认条目,但尚未确认。
You can find more information on these two Settings here
您可以在此处找到有关这两个设置的更多信息
回答by JKoko
To ensure that this is backwards compatible with iOS 7, you should check whether the user is running iOS 8 or iOS 7. For example:
为确保这与 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];
回答by neo D1
- (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
}
And to your info.plist File

和你的 info.plist 文件

回答by metatheoretic
According to the Apple docs:
根据苹果文档:
- https://developer.apple.com/documentation/corelocation/requesting_permission_to_use_location_services
- https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization
- https://developer.apple.com/documentation/corelocation/requesting_permission_to_use_location_services
- https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization
As of iOS 8, the presence of a NSLocationWhenInUseUsageDescriptionor a NSLocationAlwaysUsageDescriptionkey value in your app's Info.plist file is required. It's then also necessary to request permission from the user prior to registering for location updates, either by calling [self.myLocationManager requestWhenInUseAuthorization]or [self.myLocationManager requestAlwaysAuthorization]depending on your need. The string you entered into the Info.plist will then be displayed in the ensuing dialog.
从 iOS 8 开始,您的应用程序的 Info.plist 文件中需要存在 aNSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription键值。然后,还需要在注册位置更新之前通过电话[self.myLocationManager requestWhenInUseAuthorization]或[self.myLocationManager requestAlwaysAuthorization]根据您的需要请求用户的许可。您在 Info.plist 中输入的字符串将显示在随后的对话框中。
If the user grants permission, it's business as usual. If they deny permission, then the delegate is not informed of location updates.
如果用户授予权限,则一切照旧。如果他们拒绝许可,则不会通知代表位置更新。
回答by Adarsh G J
- (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];
}
}
In iOS 8 you need to do two extra things to get location working: Add a key to your Info.plist and request authorization from the location manager asking it to start. There are two Info.plist keys for the new location authorization. One or both of these keys is required. If neither of the keys are there, you can call startUpdatingLocation but the location manager won't actually start. It won't send a failure message to the delegate either (since it never started, it can't fail). It will also fail if you add one or both of the keys but forget to explicitly request authorization. So the first thing you need to do is to add one or both of the following keys to your Info.plist file:
在 iOS 8 中,你需要做两件额外的事情来让定位工作:向你的 Info.plist 添加一个密钥,并请求定位管理器的授权,要求它启动。新位置授权有两个 Info.plist 密钥。需要这些密钥中的一个或两个。如果两个键都不存在,您可以调用 startUpdatingLocation 但位置管理器实际上不会启动。它也不会向委托发送失败消息(因为它从未启动,所以不会失败)。如果您添加一个或两个密钥但忘记明确请求授权,它也会失败。因此,您需要做的第一件事是将以下一个或两个键添加到您的 Info.plist 文件中:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
Both of these keys take a string
这两个键都接受一个字符串
which is a description of why you need location services. You can enter a string like “Location is required to find out where you are” which, as in iOS 7, can be localized in the InfoPlist.strings file.
这是您需要定位服务的原因的描述。您可以输入类似“Location is required to find your where you are”这样的字符串,就像在 iOS 7 中一样,可以在 InfoPlist.strings 文件中进行本地化。


回答by Yinfeng
My solution which can be compiled in Xcode 5:
我的解决方案可以在 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];
回答by Nits007ak
The old code for asking location won't work in iOS 8. You can try this method for location authorization:
旧的询问位置的代码在 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];
}
}
回答by Nits007ak
In iOS 8 you need to do two extra things to get location working: Add a key to your Info.plist and request authorization from the location manager asking it to start
在 iOS 8 中,你需要做两件额外的事情来让定位工作:向你的 Info.plist 添加一个密钥并请求定位管理器的授权,要求它启动
info.plist:
信息.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>
Add this to your code
将此添加到您的代码中
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
回答by st.derrick
One common error for Swift developers:
Swift 开发人员的一个常见错误:
First make sure you add a value to the plist for either NSLocationWhenInUseUsageDescriptionor NSLocationAlwaysUsageDescription.
首先确保您为 plist 添加了一个值NSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription。
If you are stillnot seeing a window pop up asking for authorization, look to see if you are putting the line var locationManager = CLLocationManager()in your View Controller's viewDidLoadmethod. If you do, then even if you call locationManager.requestWhenInUseAuthorization(), nothing will show up. This is because after viewDidLoad executes, the locationManager variable is deallocated (cleared out).
如果您仍然没有看到请求授权的弹出窗口,请查看您是否var locationManager = CLLocationManager()在视图控制器的viewDidLoad方法中添加了该行。如果您这样做,那么即使您调用locationManager.requestWhenInUseAuthorization(),也不会显示任何内容。这是因为在 viewDidLoad 执行后,locationManager 变量被释放(清除)。
The solution is to locate the line var locationManager = CLLocationManager()at the top of the class method.
解决方法是var locationManager = CLLocationManager()在类方法的顶部定位该行。

