ios - 后台和暂停应用模式下的位置更新

标签 ios ios7 nstimer cllocationmanager

我想编写每 5 分钟发送到服务器低精度位置的应用程序,它的两种模式:前台和后台。因为我不想减少电池电量,并且 locationSignificantChange 只提供高精度值,所以我每 5 分钟从 GPS 启动/停止 locationUpdates。应用程序在前台模式下工作正常,但在后台模式下仅工作约 1 小时(之后停止发送位置)。我想我在 backgroundTask/NSTimer 代码中遗漏了一些东西,因为我是 iOS 新手。我将非常感谢您的帮助。该应用程序仅适用于 iOS 7 及更高版本。

一般来说,我的算法如下:

** start backGroundTask
** [_locationManager startUpdatingLocation]
** handle received location in "didUpdateLocations:" listener
** [_locationManager stopUpdatingLocation]
** create new thread and fire the NSTimer with delay 5 min
** end backGroundTask

这是我的代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [self startLocationManager];
        // .. other init app code
}



- (void) startLocationManager {
          _locationManager = [[CLLocationManager alloc] init];
          _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
          _locationManager.distanceFilter = 10;
          _locationManager.delegate = self;
          _locationManager.pausesLocationUpdatesAutomatically = NO;
          [_locationManager startLocation];
}



- (void) startLocation {
    UIApplication * app = [UIApplication sharedApplication];
    self.bkgdTask = [app beginBackgroundTaskWithExpirationHandler:^{
    }];
    [self.locationManager startUpdatingLocation];
}



- (void) stopUpdatingLocation {

    [_locationManager stopUpdatingLocation];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
       self.locationNextTimer =  [NSTimer scheduledTimerWithTimeInterval:5 * 60
                                                                 target:self
                                                                 selector:@selector(startLocation)
                                                                 userInfo:nil
                                                                 repeats:NO];
        [[NSRunLoop currentRunLoop] addTimer:self.locationNextTimer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
        [app endBackgroundTask:self.bkgdTask];
        self.bkgdTask = UIBackgroundTaskInvalid;
     });
}



- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
       [self.locationNextTimer invalidate];
       self.locationNextTimer = nil;
       //ToDo  Location Handling
       [self stopUpdatingLocation];
}

编辑:

正如我从 iOS7 中了解到的那样,Apple 希望 locationManager 的 startUpdatingLocation 只能从前台完成。那么解决这个问题的任何想法?
我还尝试了其他解决方案:使用 NSTimer 代替 stop/startUpdatingLocation,以使用 NSTimer 更改大/小值的精度和距离过滤器。它不起作用,因为我在“didUpdateLocations:”监听器中收到了 4 次“高速公路驱动”的触发器,而不是一次。

最佳答案

位置管理器将根据您的设置自行决定最少的事件。根据您的用例设置参数,然后在您的委托(delegate)中负责任地采取行动。测试收到的位置,如果它们太新,那么你什么也不做。这将使您的应用程序处理尽可能少地影响电池。
significantLocationChanges旨在减少影响,并且根据我的经验,它做得很好。另一种选择是使用区域监控来代替或同时使用。

您可以通过根据您希望达到的精度创建大小的区域来进一步限制事件。仅在跨越边界时更新区域并保存位置。这可能更适合您的需求。

关于ios - 后台和暂停应用模式下的位置更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21220245/

相关文章:

ios - 取消互联网连接不良时的解析重试

crash - 当NSTimer触发reloadData并在iPad上的iOS 7中启用退信时,UICollectionView偶尔崩溃

ios - 使用 NSTimer 调用 performSelectorOnMainThread

ios - 尝试在 Delphi 中编译 64 位 iOS 设备

iOS JavaScriptCore.framework 验证

xcode - IOS7(仅)stdlibc++ 链接问题

ios - 使用 swift 在 ios7 上替代 QOS_CLASS_UTILITY

ios - iOS 中 Core Animation 和 UIKit Dynamics 的区别

ios - Xcode Obj-C 无法打开输出文件进行写入,架构 x86_64 的 errno=21

objective-c - 在 iOS 中再次从其自己的委托(delegate)中打开 UIAlertView 失败