繁体   English   中英

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

[英]Location Services not working in iOS 8

我在 iOS 7 上运行良好的应用程序不适用于 iOS 8 SDK。

CLLocationManager不返回位置,我也没有在“设置” ->“位置服务”下看到我的应用程序。 我对这个问题进行了谷歌搜索,但没有任何结果。 可能有什么问题?

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

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

Info.plist还需要有NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription键,并在提示中显示一条消息。 添加这些解决了我的问题。

在此处输入图片说明

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

我正在用同样的问题拉我的头发。 Xcode 给你错误:

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

但即使您实现了上述方法之一,它也不会提示用户,除非 info.plist 中有NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

将以下行添加到您的 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];
- (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 文件中需要存在NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription键值。 然后还需要在注册位置更新之前请求用户的许可,根据您的需要调用[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 文件中:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

这两个键都需要一个字符串

这是您需要定位服务的原因的描述。 您可以输入类似“Location is required to find your where you are”这样的字符串,就像在 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];
    }
}

在 iOS 8 中,你需要做两件额外的事情来让定位工作:向你的 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>

将此添加到您的代码中

if (IS_OS_8_OR_LATER)
{
    [locationmanager requestWhenInUseAuthorization];

    [locationmanager requestAlwaysAuthorization];
}

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

首先确保为NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription添加一个值到 plist。

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

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

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

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

编辑您的应用程序的Info.plist并添加键NSLocationAlwaysUsageDescription和将显示给用户的字符串值(例如, We do our best to preserve your battery life.

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

requestAlwaysAuthorizationrequestWhenInUseAuthorization

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

我正在开发一个升级到 iOS 8 的应用程序,但位置服务停止工作。 您可能会在 Debug 区域中得到和错误,如下所示:

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

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

在此处输入图片说明

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

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

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

在此之后locationManager:didChangeAuthorizationStatus:方法被调用:

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

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

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

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 个键。

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

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

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

}

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

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

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

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

}

我在 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

进入 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 图像

  1. 添加键NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription (背景 GPS 使用)和字符串,要求在每个目标的每个info.plist上使用 GPS。

  2. 通过运行请求许可:

    [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 中进行本地化。 在我的测试中,这些键可以直接在文件InfoPlist.strings配置。

因此,您需要做的第一件事是将 > 以下键中的一个或两个添加到您的 Info.plist 文件中:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

这两个键都采用一个字符串,它描述了您为什么需要位置服务。 您可以输入类似“Location is required to find your where you are”这样的字符串,就像在iOS 7 中一样,可以在 InfoPlist.strings 文件中进行本地化。


更新:

我认为@IOS的方法更好。 使用空值向Info.plist添加键,并将本地化字符串添加到InfoPlist.strings

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM