我的应用在iOS 7上运行良好,但在iOS 8 SDK上却无法运行。

CLLocationManager不返回位置,我没有看到我的应用程序下设置->位置服务。我在这个问题上做了谷歌搜索,但没有任何结果。会有什么问题呢?


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

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

在Info中还需要NSLocationAlwaysUsageDescription或NSLocationWhenInUseUsageDescription键。Plist并在提示符中显示一条消息。加上这些就解决了我的问题。

更多详细信息,请查看:Core-Location-Manager-Changes-in-ios-8


我也因为同样的问题而抓狂。Xcode给出错误:

试图启动MapKit位置更新而没有提示 位置授权。必须调用-[CLLocationManager requestWhenInUseAuthorization]或-[CLLocationManager . request requestAlwaysAuthorization]。

但即使实现了上述方法之一,它也不会提示用户,除非信息中有条目。NSLocationAlwaysUsageDescription或NSLocationWhenInUseUsageDescription。

添加以下行到您的信息。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可能会为这些键添加默认条目,但还没有确认。

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


苹果的文件显示:

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 NSLocationWhenInUseUsageDescription or a NSLocationAlwaysUsageDescription key 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 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];

向后兼容解决方案:

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键


解决方案与向后兼容,不产生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版本11.0+: 在Info.plist中设置NSLocationAlwaysAndWhenInUseUsageDescription键。还有另外2把钥匙。


我的解决方案可以在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];
    }
}

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


}

还有你的信息。plist文件


在iOS 8中,你需要做两件额外的事情来让定位工作:给你的信息添加一个键。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];
}

一个小帮手,为所有你有一个以上的信息。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' {} 

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


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

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

编辑应用程序的信息。并添加键NSLocationAlwaysUsageDescription与字符串值,将显示给用户(例如,我们尽我们最大的努力来保持您的电池寿命。)

如果你的应用程序只在应用程序打开时需要位置服务,请替换:

requestAlwaysAuthorization with requestWhenInUseAuthorization和

NSLocationAlwaysUsageDescription和NSLocationWhenInUseUsageDescription。


添加关键NSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription(后台GPS使用)字符串要求使用GPS在每个信息。Plist从每个目标。 通过运行命令获得许可: (自我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];
}

记住,如果键不是在每个信息上。Plist为每个目标,应用程序将不会询问用户。if提供了与iOS 7的兼容性,respondsToSelector:方法保证了未来的兼容性,而不仅仅是解决iOS 7和8的问题。


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

NSLocationAlwaysUsageDescription in the Info.plist 

这将询问用户获取其当前位置的权限。


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

}

对于那些使用Xamarin,我必须添加关键NSLocationWhenInUseUsageDescription的信息。手动plist,因为在Xamarin 5.5.3 Build 6或XCode 6.1的下拉列表中都不可用-只有NSLocationUsageDescription在列表中,这导致CLLocationManager继续无声地失败。


我当时在开发一款升级到iOS 8的应用,位置服务停止了。你可能会在Debug区域得到一个错误,如下所示:

试图启动MapKit位置更新而没有提示位置授权。必须先调用-[CLLocationManager requestWhenInUseAuthorization]或-[CLLocationManager requestAlwaysAuthorization]。

我做了侵入性最小的手术。首先添加NSLocationAlwaysUsageDescription条目到你的info.plist:

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

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

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

之后locationManager:didChangeAuthorizationStatus:方法为call:

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

现在一切正常。和往常一样,请查看文档。


- (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:

NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription

这两个键都有一个字符串

这就是为什么你需要位置服务。你可以 输入一个字符串,如“位置是必须找到你在哪里” 和iOS 7一样,可以在InfoPlist中进行本地化。字符串文件。


Swift开发者常犯的一个错误:

首先确保你添加了一个值到plist为NSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription。

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

解决方案是在类方法的顶部找到var locationManager = CLLocationManager()行。


对我来说,问题是CLLocationManagerDelegate类是私有的,这阻止了所有的委托方法被调用。我想这不是很常见的情况,但我想我应该提到它,以防它能帮助到任何人。


我在InfoPlist中添加了这些键。字符串在iOS 8.4, iPad mini 2。这也很有效。我没有在Info.plist中设置任何键,比如NSLocationWhenInUseUsageDescription。


InfoPlist.strings:

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

基于这个线程,它说,就像在iOS 7中一样,可以本地化到InfoPlist.strings中。在我的测试中,这些键可以直接在InfoPlist.strings文件中配置。

因此,您需要做的第一件事是将>下面的一个或两个键添加到您的Info中。plist文件: NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription 这两个键都有一个字符串,用来描述你为什么 需要位置服务。您可以输入一个字符串,例如“Location is” 需要知道你在哪里”,这在iOS 7中是可以做到的 在InfoPlist中本地化。字符串文件。


更新:

我认为@IOS的方法更好。将键添加到信息。将本地化的字符串添加到InfoPlist.strings中。


保持可可钥匙信息总是在你的指尖为这些更新,这里是链接:

https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW26

享受。


这是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>

我在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 取值范围:应用需要为员工提供位置服务器


为了访问用户在iOS中的位置。您需要添加两个键

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

进入信息。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>

请看下图。


objective - c程序 遵循以下指示:

对于iOS-11 对于iOS 11,看看这个答案:iOS 11位置访问

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

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

对于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];
}

迅速的过程

遵循以下指示:

对于iOS-11 对于iOS 11,看看这个答案:iOS 11位置访问

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

 1. NSLocationAlwaysAndWhenInUseUsageDescription 
 2. NSLocationWhenInUseUsageDescription
 3. NSLocationAlwaysUsageDescription

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

委托方法

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

}