位置服务在iOS 8中不起作用

时间:2014-06-05 14:12:06

标签: objective-c ios8 location cllocationmanager

我在iOS 7上运行良好的应用无法与iOS 8 SDK配合使用。

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

26 个答案:

答案 0 :(得分:1085)

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

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

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

enter image description here

希望它可以帮助别人。

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

答案 1 :(得分:312)

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

  

尝试在不提示的情况下启动MapKit位置更新   位置授权。必须先致电-[CLLocationManager requestWhenInUseAuthorization]-[CLLocationManager requestAlwaysAuthorization]

但即使您实施上述方法之一,它也不会提示用户,除非{。1}}或NSLocationAlwaysUsageDescription的info.plist中有条目。

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

NSLocationWhenInUseUsageDescription

我认为自从我在Xcode 5中启动此项目后,这些条目可能已经丢失。我猜测Xcode 6可能会为这些密钥添加默认条目但尚未确认。

您可以在这两个设置here

上找到更多相关信息

答案 2 :(得分:104)

为确保向后兼容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 :(得分:50)

- (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文件 enter image description here

答案 4 :(得分:30)

根据Apple文档:

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

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

答案 5 :(得分:28)

- (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文件中进行本地化。

enter image description here

答案 6 :(得分:19)

我的解决方案可以在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 :(得分:17)

询问位置的旧代码在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 :(得分:12)

在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 :(得分:11)

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

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

如果您仍然没有看到弹出要求授权的窗口,请查看您是否将行var locationManager = CLLocationManager()放入View Controller的viewDidLoad } 方法。如果您这样做,那么即使您致电locationManager.requestWhenInUseAuthorization(),也不会显示任何内容。这是因为在viewDidLoad执行之后,将取消分配(清除)locationManager变量。

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

答案 10 :(得分:9)

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

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

修改您的应用Info.plist并添加键NSLocationAlwaysUsageDescription,其中包含将向用户显示的字符串值(例如,We do our best to preserve your battery life.

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

requestAlwaysAuthorization requestWhenInUseAuthorization

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

答案 11 :(得分:9)

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

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

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

Enter image description here

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

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

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

此后调用locationManager:didChangeAuthorizationStatus:方法:

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

现在一切正常。与往常一样,请查看documentation

答案 12 :(得分:7)

具有向后兼容性的解决方案:

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 :(得分:6)

具有向后兼容性且不会产生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];
}

NSLocationWhenInUseUsageDescription中设置Info.plist密钥。

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

答案 14 :(得分:5)

这是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 :(得分:4)

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

适用于iOS-11 对于iOS 11,请查看此答案:iOS 11 location access

需要在plist中添加两个键并提供如下图所示的信息:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

enter image description here 适用于iOS-10及以下版本:

NSLocationWhenInUseUsageDescription

enter image description here

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 location access

需要在plist中添加两个键并提供如下图所示的信息:

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

enter image description here 适用于iOS-10及以下版本:

enter image description here

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

}

答案 16 :(得分:4)

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

NSLocationAlwaysUsageDescription in the Info.plist 

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

答案 17 :(得分:3)

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

答案 18 :(得分:2)

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

}

答案 19 :(得分:2)

答案 20 :(得分:2)

我在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 :(得分:2)

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

答案 22 :(得分:2)

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

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

答案 23 :(得分:1)

  1. 添加密钥NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription(使用后台GPS),并在每个目标的每个info.plist上使用字符串。

  2. 通过运行来获取许可:

    [self initLocationManager:locationManager];

  3. 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 :(得分:0)

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

答案 25 :(得分:0)

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

InfoPlist.strings

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

Base on this thread,它说,as in iOS 7,可以在InfoPlist.strings中进行本地化。在我的测试中,可以直接在文件InfoPlist.strings中配置这些密钥。

  

所以你需要做的第一件事就是添加一个或两个&gt;以下密钥到您的Info.plist文件:

     
      
  • NSLocationWhenInUseUsageDescription
  •   
  • NSLocationAlwaysUsageDescription
  •   
     

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

<强>更新

我认为@IOS's method is better.使用空值为Info.plist添加密钥,并将本地化字符串添加到InfoPlist.strings