iOS 后台定位 蓝条问题

3,195 阅读5分钟

首先对于定位功能实现的问题,详见这幅帖子,超级全面详细:【iOS】7.4 定位服务->2.1.2 定位 - 官方框架CoreLocation: CLLocationManager(位置管理器)

一、开启定位权限的配置

iOS定位权限自从iOS8之后就改动很多,出于对用户隐私方面来说,如果要调用GPS模块,就必须经过用户确定,体现在应用弹窗让用户选择。需要在info.plist文件添加3个授权

  • a. Privacy - Location When In Use Usage Description (应用使用期间),
  • b. Privacy - Location Always Usage Description(始终允许),
  • c. Privacy - Location Always and When In Use Usage Description(始终允许,iOS11新增)
在iOS11时,Privacy - Location Always and When In Use Usage Description表示始终允许,Location Always Usage Description在功能上被降级为为“应用使用期间”。

如果a,b两项添加到plist里,授权提示有2个选择项

定位授权弹窗一
如果a,b,c 全部添加到plist里,授权提示有3个选择项

定位授权弹窗二

那么当我们允许应用使用GPS获取位置信息之后,我们在设置-隐私-定位服务 找到自己的应用点进去可以看到如下 upload-images.jianshu.io/upload_imag…

有三个选项: 1.永不 2.使用应用期间 3.始终。

  • 永不:不给定位权限
  • 使用应用期间:应用在前台运行状态才获取定位信息
  • 始终:包括应用在后台也能获取定位信息

一般情况下,在info.plist文件中,将以上三条都配置上.

当然,有的情况下只需两个选择:

  • 1.永不 2.使用应用期间
    info.plist只设置了NSLocationWhenInUseUsageDescription

  • 1.永不 2.始终

    info.plist只设置了NSLocationAlwaysUsageDescription和NSLocationAlwaysAndWhenInUseUsageDescription (今天在iPhone7 plus iOS12.1.4系统 怎么试都不显示定位选择弹框,不知道咋回事,你们可以尝试下,告知下我结果)。

一般除了导航、运动类App才会用到

二、实现后台定位

对于一些运动类、导航类App,可能计时应用退到了后台也要获取用户的位置信息,该功能的实现我们姑且称为:后台定位。

首先,在TARGETS->Capabilities->Background Modes中,开启开关,并且Location updates选项勾选上。

第一步在info.plist文件中配置好了获取用户隐私权限后,第一次登入App,用户会收到一个定位授权弹窗。根据用户的选择情况,会走CLLocationManagerDelegate协议中的- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status方法。当然,也可以通过CLAuthorizationStatus status = [CLLocationManager authorizationStatus];获取当前用户选择的授权状态,然后进行判断做相应逻辑处理。一般处理如下:

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    NSLog(@"定位:   %d",status);
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"用户未做选择");//可以提示跳转到设置
            break;
        case kCLAuthorizationStatusRestricted:
            NSLog(@"定位被限制");
            break;
        case kCLAuthorizationStatusDenied:
            NSLog(@"用户拒绝获取定位");
            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            //用户同意永久访问定位
            [self.locationManager requestAlwaysAuthorization];
            break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            //用户允许使用应用期间访问定位
            [self.locationManager requestWhenInUseAuthorization];
            break;
        default:
            break;
    }
}

三、关于蓝条问题的产生机理和处理办法

这种蓝条问题的产生和解决。

CLLocationManager管理类的配置

_locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    _locationManager.distanceFilter = 100;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    if ([[UIDevice currentDevice] systemVersion].floatValue >= 8) {
        /*
         有这么一种说法
         如果两个请求授权的方法都执行了,会出现以下情况
         1.requestWhenInUseAuthorization写在前面,第一次打开程序时请求授权,如果勾选了后台模式,进入后台会出现蓝条提示正在定位。当程序退出,第二次打开程序时requestAlwaysAuthorization 会再次请求授权。之后进入后台就不会出现蓝色状态栏。
         2.requestAlwaysAuthorization写在前面, requestWhenInUseAuthorization写在后面,只会在第一次打开程序时请求授权,因为requestAlwaysAuthorization得到的授权大于requestWhenInUseAuthorization得到的授权
         */
        [_locationManager requestAlwaysAuthorization];
        [_locationManager requestWhenInUseAuthorization];
    }
    if ([[UIDevice currentDevice] systemVersion].floatValue >= 9) {
        /*
         allowsBackgroundLocationUpdates:是否允许后台定位,默认为NO,只在iOS9.0之后起作用。
         设为YES时,必须保证Background Modes 中的Location updates处于选中状态,否则会抛出异常。
         在用户选择仅在使用应用期间获取位置权限的情况下,当应用进入后台,手机桌面顶部是否出现蓝条,这句代码起着关键性作用。
         首先,这句代码仅在requestWhenInUseAuthorization状态下才起作用,否则不起作用。当设为YES,就是允许在requestWhenInUseAuthorization此状态下,即使App进入后台,但是没杀死,那么就依然可以后台定位。并且顶部给个蓝条闪烁,目的是在于实时提醒用户:你这个App一直在获取你的位置信息哟,如果你感到不需要继续获取了,就杀死该App吧!所以一直蓝条闪烁。
         当设置为NO,就是在requestWhenInUseAuthorization状态下,App进入后台,立即停止后台定位。
         */
        _locationManager.allowsBackgroundLocationUpdates = YES;
        /*
         requestLocation和startUpdatingLocation这两个方法非常类似,都会立即返回结果,将获取的定位信息传递给委托对象的locationManager:didUpdateLocations:消息。
         不同点:
         startUpdatingLocation:可以持续获取定位。当设备移动的距离超过设定的distanceFilter属性值时,接收器会再次生成一条更新消息。
         requestLocation:只产生一次定位信息,在此之后定位服务就停止了。并且:当使用这个方法时,委托对象必须要实现locationManager:didUpdateLocations:和locationManager:didFailWithError:方法。
         */
        [_locationManager requestLocation];
    } else {
        [_locationManager startUpdatingLocation];
        
    }

其实在上段代码注释中已经写得较清楚了。

  • 蓝条问题的产生前提:只在requestWhenInUseAuthorization这个状态下才会出现。

  • 蓝条出现的目的:因为用户选择的是仅在应用使用期间获取位置,所以当app进入后台后,系统将以蓝条闪烁的形式不断提醒用户:主人,某某App一直在后台获取你的位置权限哟,如果你不需要用到了,你就直接将该App杀死吧,不然挺耗电的,如果有需要就当我没说哈。

  • 蓝条出现与否的背后代码操控者:_locationManager.allowsBackgroundLocationUpdates = YES;如果不想出现蓝条,直接设置为NO,或者注释,因为默认为NO。

  • 另外,蓝条出现与否的另一种说法:跟下面两句代码的执行顺序有关

        [_locationManager requestAlwaysAuthorization];
        [_locationManager requestWhenInUseAuthorization];

详见代码注释。

四、一张很经典的表格

此表早已包罗万象,望各位施主早日参透

告辞!