iOS9中CLLocationManager中的allowsBackgroundLocationUpdates

65
我正在Xcode7(预发布版)中使用CoreLocation框架,并注意到CLLocationManager类中新增了一个名为allowsBackgroundLocationUpdates的属性。

这个属性与“能力”标签下的“后台模式”中的位置更新有什么关系?它的默认值是什么?它是否会影响在iOS9上运行的应用程序?

6个回答

109

这个新属性在WWDC会议的 "Core Location的新功能"中有介绍。

如果你链接的是iOS 9,则默认值为NO

如果您的应用在后台使用位置服务(不显示蓝色状态栏),则必须将allowsBackgroundLocationUpdates设置为YES,并在Info.plist中设置背景模式能力,否则位置更新仅在前台提供。优点是您现在可以在同一应用程序中拥有具有后台位置更新和< strong>其他仅具有前台位置更新的位置管理器。您还可以将该值重置为NO以更改行为。

文档对此非常清楚:

默认情况下,无论最小部署目标如何,针对iOS 9.0或更高版本链接的应用程序都不会启用此选项。

当UIBackgroundModes在Info.plist中包括“location”时,每次调用-startUpdatingLocation并打算在后台继续时,您必须在运行时将此属性设置为YES。

当UIBackgroundModes不包括“location”时,将此属性设置为YES是致命错误。

将此属性重置为NO等效于省略UIBackgroundModes值中的“location”。仍然允许访问位置,只要应用程序正在运行(即未挂起),并且具有足够的授权(即具有在使用中的WhenInUse授权或始终授权)。但是,该应用程序仍将受到常规任务暂停规则的限制。

有关可能的授权值的更多详细信息,请参见-requestWhenInUseAuthorization和-requestAlwaysAuthorization。


7
我认为这个属性会造成混淆而不是明晰。我们拥有(并仍然拥有)“始终”和“使用时”属性,它们非常清晰。为什么要加入这样令人困惑的属性呢?而且我认为使用多个 CLLocationManager 对象不是最佳实践。 - androniennn
这个属性在后台区域监测或显著位置变化监测中是否必要,还是requestAlwaysAuthorization足够好? - Awesome-o
我遇到了一个奇怪的问题,就是在禁用allowsBackgroundLocationUpdates之后,它仍然在工作。也许你可以帮助我解决这个问题。https://dev59.com/s57ha4cB1Zd3GeqPhEpu - Sander

45
如果您在Xcode7(预发布版)中的应用程序中使用CoreLocation框架,并且您可能会注意到CLLocationManager类中新增了一个名为allowsBackgroundLocationUpdates的属性。
这个新属性在WWDC会议"Core Location中的新内容"中有解释。默认值是NO,如果您链接到iOS 9。
如果您的应用程序在后台使用位置(没有显示蓝色状态栏),则必须除了在Info.plist中设置后台模式功能之外,还要将allowsBackgroundLocationUpdates设置为YES。否则,位置更新仅在前景中交付。优点是您现在可以在同一应用程序中拥有具有后台位置更新和仅前景位置更新的位置管理器。您也可以将该值重置为NO以更改行为。
文档对此非常清楚:
默认情况下,无论最低部署目标如何,针对 iOS 9.0 或更高版本链接的应用程序都为 NO。在 Info.plist 中将 UIBackgroundModes 设置为包括“location”时,每次在后台调用 -startUpdatingLocation 时,您还必须在运行时将此属性设置为 YES。当 UIBackgroundModes 不包括“location”时,将此属性设置为 YES 是致命错误。将此属性重置为 NO 等效于从 UIBackgroundModes 值中省略“location”。只要应用程序正在运行(即未挂起),并且具有足够的授权(即具有 WhenInUse 授权并正在使用,或者具有 Always 授权),就仍然可以访问位置。但是,该应用程序仍将受到通常的任务暂停规则的限制。有关可能的授权值的更多详细信息,请参见 -requestWhenInUseAuthorization 和 -requestAlwaysAuthorization。将 Info.plist 设置为以下内容: enter image description here Info.plist 配置的语法如下:
<key>NSLocationAlwaysUsageDescription</key>
<string>I want to get your location Information in background</string>

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

或者打开您的应用程序目标的“功能”选项卡。

在此输入图片描述
(来源:raywenderlich.com)

使用方式:

_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
    [_locationManager requestAlwaysAuthorization];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
    _locationManager.allowsBackgroundLocationUpdates = YES;
}
[_locationManager startUpdatingLocation];

我写了一个演示 这里 (Demo2)


你是否遇到了这个标志的问题?在我的示例项目中,如果它最初设置为true,则禁用它不起作用。https://dev59.com/s57ha4cB1Zd3GeqPhEpu - Sander

6
{
NSArray* backgroundModes  = [NSBundle MainBundle].infoDictionary[@"UIBackgroundModes"];

     if(backgroundModes && [backgroundModes containsObject:@"location"]) {
         if([manager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
             // We now have iOS9 and the right capabilities to set this:
             [manager setAllowsBackgroundLocationUpdates:YES];
         }
     }
}

只是小写字母拼错了,MainBundle 应该是小写的 m。mainBundle = [NSBundle mainBundle]; - mauron85

5

我在iOS 9.0.x的后台模式中遇到了相同的位置服务问题,按照这篇文章的建议添加以下代码进行修复:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
    _locationManager.allowsBackgroundLocationUpdates = YES;
}

但是在iOS 9.1上无法使用。有没有人遇到相同的问题?如果是,请帮忙解决。谢谢。


我在iOS 9.1上遇到了同样的问题。 - franck
@Franck,我遇到了完全相同的问题,你解决了吗? - ASBai
@ASBai 抱歉,不是这样的。现在它对我来说可以工作了,而且我也不明白发生了什么。 - franck
@franck,你在XCode的“后台模式”页面中启用了“音频、AirPlay和PIP…”选项吗? - ASBai
@franck 是的,但它仍然无法工作。不管怎样,感谢您的回复 :-) - ASBai
我在iOS 9.1中遇到了同样的问题。我不知道该如何解决它。如果你已经找到了解决方案,请帮忙一下。 - Md Rais

5

我仍在使用xCode 6,因为7 beta版本总是与模拟器崩溃,并且即使我不链接到iOS9,我也遇到了这个问题!而且我无法设置此属性,因为它在iOS8中不存在!哦,苹果,煎熬何时才能结束?!

我通过进行后期绑定调用将其更改为此xCode6兼容版本:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0) {

            BOOL yes = YES;

            NSMethodSignature* signature = [[CLLocationManager class] instanceMethodSignatureForSelector: @selector( setAllowsBackgroundLocationUpdates: )];
            NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: signature];
            [invocation setTarget: locationManager];
            [invocation setSelector: @selector( setAllowsBackgroundLocationUpdates: ) ];
            [invocation setArgument: &yes atIndex: 2];
            [invocation invoke];
        }

已确认在iOS8上可以使用(不会产生任何效果),同时在iOS9 beta 6上可以正确调用方法。


0

这里是从iOS 8到iOS 9更新的许多方法的摘要。

许多API和代码应该针对您正在使用的每个框架进行搜索。因此,先在通用框架中搜索,然后找到这些方法以更新过时的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接