【问题标题】:ios deferred location updates fail to deferios 延迟位置更新未能延迟
【发布时间】:2014-06-14 14:10:59
【问题描述】:

我正在研究为 iOS 活动跟踪器使用延迟位置更新,它允许在后台提供位置服务。我已经实现了建议的代码 sn-ps(见下文)。在 Xcode 调试中,延迟位置会尝试启动几次,直到位置数据以每秒 1 次左右的速度进入。之后,它声称启动deferrals成功,并且finish触发器的回调在指定的时间段到期后也成功。但是,在此期间,位置处理程序仍每秒运行一次。我读到这是因为手机还没有认为自己准备好进入后台,而 Xcode 中的测试就是这样做的。注意,AppDelegate 的“didEnterBackground”事件处理程序在关闭屏幕时立即被调用,并在重新打开应用程序时恢复。

我在手机断开连接的情况下运行了相同的代码,在 GPS 窗口附近、屏幕关闭或切换到完全不同的应用程序时,它仍然从未真正推迟更新。我可以判断,因为网络更新仍然每 30 秒进行一次,而不是下面代码示例中所需的 120 秒间隔。

实际上还需要什么才能使延迟起作用,因为在启动它们时没有发生错误并且它们确实得到了完成回调?为什么即使应用进入后台,位置更新也会以每秒 1 次的速度继续?

iPhone 5s,IOS 7.1.1

// .h file (partial)
@interface MotionTracker : NSObject<CLLocationManagerDelegate, UIAccelerometerDelegate> 

@property (strong, nonatomic) CLLocationManager *locationManager;

@end

// .m file (parial)
- (id) init {
    if(self = [super init]){
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.distanceFilter = kCLDistanceFilterNone; 
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;

        // if set to YES (default), app stops logging location at some point and doesn't resume in any timely fashion, all data points lost in between
        _locationManager.pausesLocationUpdatesAutomatically = NO;

        _locationManager.activityType = CLActivityTypeFitness; 
    }
    return self;
}

// called early in program after login confirmed
- (void) startCollectingLocation {
    [_locationManager startUpdatingLocation];
}    

- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations {

    // logs to file when device is not in debug
    // always returns 1
    NSLog(@"Location update count: %d",[locations count]);

    // some code here to handle location updates
    // - collect key location day in NSDictionary
    // - every N seconds send Network call to server to save (have tried 30 seconds, 15 minutes, 30 minute network intervals). Have also tried turning off network calls completely.


    // deferred updates starter
    if (!self.deferringUpdates) {
        if([CLLocationManager deferredLocationUpdatesAvailable]){
            [_locationManager allowDeferredLocationUpdatesUntilTraveled:500 timeout:(NSTimeInterval)120]; // (have also tried large numbers, and "Infinite"
            self.deferringUpdates = YES;
            NSLog(@"Deferred updates start");
        } else {
            NSLog(@"Deferred updates not available");
        }
    }
}

- (void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {
    if(!error){
        _deferringUpdates = NO;
        NSLog(@"Deferred updates: finished");
    } else {
        _deferringUpdates = NO;
        NSLog(@"Deferred updates: %@", [error localizedDescription]);
    }
}

【问题讨论】:

  • 您是否完成了this answer 中列出的所有操作?在该列表之后的大部分时间里,我都能让它工作。
  • 是的,我已经完成了该列表中的所有内容并检查了几次。那里的大部分内容似乎都很基本。
  • 其中一个关键是等待位置更新定期进入,然后再启用延迟更新。即使这样,系统也不会一直启用它,这取决于设备上的其他内容。如果它对你有用,即使只是一次,那么你就做对了,这只是由系统决定何时让 CPU 休眠。
  • 它从来没有工作过。我最初立即调用它,它会给出错误代码,直到 GPS 完全启动,然后运行没有错误但仍然没有延迟。然后我在尝试第一次调用之前等待了 15 秒,不再收到错误代码,但仍然没有运气。我已经让它在调试器上运行了几个小时,屏幕关闭。我已经在设备上独立运行它,并完成了离线日志记录,让它在一夜之间运行,基本上直到电池从所有位置更新中耗尽 12 小时以上。我不确定还需要什么来让 CPU 休眠。
  • 连接到调试器时设备从不休眠。

标签: ios location core-location deferred


【解决方案1】:

如果设备连接到调试器或充电器,设备将保持供电(非睡眠),因此不会进入延迟模式。延迟模式是一种允许设备休眠的电源优化。如果设备因其他原因未计划睡眠,则启用延迟模式不会强制其进入睡眠状态。通过确保没有其他应用程序正在使用定位服务,并在屏幕关闭的情况下将其与充电器断开连接,来尝试您的测试。运行一段时间后,重新插入并检查日志,您应该会看到设备已休眠并延迟更新。

来自苹果的 allowDeferredLocationUpdatesUntilTraveled:timeout: 文档:

延迟更新仅在系统进入低电量时提供 状态。调试期间不会发生延迟更新,因为 Xcode 阻止您的应用程序休眠,从而阻止系统 进入低功耗状态。

还值得注意的是,延迟更新仅在 locationManager.desiredAccuracy 设置为 kCLLocationAccuracyBest OR kCLLocationAccuracyBest 时可用; locationManager.distanceFilter 也必须设置为 kCLDistanceFilterNone。

来自 Apple 的文档:

...位置管理器仅在设备上有 GPS 硬件并且所需精度设置为 kCLLocationAccuracyBest 或 kCLLocationAccuracyBestForNavigation 时才允许延迟更新。

...位置管理器的 distanceFilter 属性必须设置为 kCLDistanceFilterNone。

【讨论】:

  • 另外值得注意的是,延迟更新仅在 locationManager.desiredAccuracy 设置为 kCLLocationAccuracyBest OR kCLLocationAccuracyBest 时可用?,您显然不是故意写两次
【解决方案2】:

我一直在为同样的问题苦苦挣扎,我可能已经找到了一个可以为许多人解决这个问题的答案 - 至少它解决了我的问题并让延迟更新始终为我工作。 我遵循this list 中的所有步骤,无论我做什么,位置更新都不会延迟。我突然想到我可能正在运行其他不允许系统睡眠的应用程序,所以我杀死了多任务托盘中的所有其他应用程序。我再次运行了我的示例应用程序......它工作了! 但故事并没有就此结束。稍后我再次尝试,即使在多任务处理托盘中没有运行其他应用程序,我也无法延迟定位服务。然后我突然想到我的手机上有一个名为“Moves”的应用程序,即使你手动杀死它,它也能保持自己的生命。我不完全确定当你杀死它时,Moves 是如何神奇地恢复生机的,但它确实如此(可能使用蓝牙和应用程序保存/恢复服务)。即使它还活着并跟踪您的位置,它也不会出现在多任务处理托盘中。我认为只有手动启动的应用程序才会出现在托盘中 - 如果操作系统启动一个应用程序,它不会出现在托盘中。但我离题了... 通过禁止 Moves 使用定位服务,我能够让延迟定位服务在我的应用中一致工作。当我这样做时,Moves 抱怨 即使它不在多任务处理托盘中。似乎如果另一个应用程序正在使用位置服务(而不是延迟),您的应用程序也不会延迟。

【讨论】:

  • 我也安装了 Moves。我稍后会检查这个。这听起来与我的经验一致。它从来没有在我的手机上运行过,但是一位同事一直在使用相同的应用程序版本运行它......
  • 延迟对 iPad 有效吗?即使我添加了外部 GPX 文件,我的 Ipad 模拟器中也经常出现 kCLErrorDeferredFailed
  • 延迟更新中交付了多少个位置?委托是在 resumeFromBackground 和 didActivate 之前还是之后调用的?谢谢
【解决方案3】:

您好,最近发布了 iOS 9 GM 种子版本,我看到位置更新(allowDeferredLocationUpdatesUntilTraveled:timeout:) 没有被延迟。用于在 iOS 8.4 及以下版本中工作的相同代码。它大量消耗我设备的电池边距。

我们需要为 iOS 9 明确设置或提及什么吗?没有从 Apple 文档中找到任何内容

这是我实现的代码。

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

if (!self.deferringUpdates) {

[self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:30]; self.deferringUpdates = YES; } }

-(void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { // 停止延迟更新 self.deferringUpdates = NO;

}

我还设置了allowBackgroundLocationUpdates 属性,但即使这样也无济于事。 self.locationManager.allowsBackgroundLocationUpdates=YES;

在 iOS 9 及更高版本中,无论部署目标如何,您还必须将位置管理器对象的 allowedBackgroundLocationUpdates 属性设置为 YES 才能接收后台位置更新。默认情况下,此属性为 NO,并且在您的应用主动需要后台位置更新之前,它应该保持这种状态。

https://developer.apple.com/library/prerelease/ios/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html

请告诉我我还需要做什么

谢谢

【讨论】:

  • 你能告诉我 - deferringUpdates 是默认值还是我们必须将此属性声明为布尔值??
  • 不,我们声明此属性以跟踪设备进入的延迟模式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
相关资源
最近更新 更多