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

时间:2014-01-19 17:39:08

标签: ios ios7 nstimer cllocationmanager

我想写一个应用程序,每5分钟发送到服务器低精度位置的两种模式:前景和后台。因为我不想减少电池电量而且locationSignificantChange只给出高精度值,所以我每隔5分钟从GPS启动/停止位置更新。应用程序在前台模式下工作正常,但距离后台模式仅约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来停止/ startUpdatingLocation,使用NSTimer更改大/小值的精度和distanceFilter。它没有用,因为我在“didUpdateLocations:”监听器中接收了4次“高速公路驾驶”而不是一次。

2 个答案:

答案 0 :(得分:2)

位置管理员将根据您的设置自行决定最少的活动。根据您的使用情况设置适当的参数,然后在您的代理中负责任地行事。测试收到的位置,如果它们太近,那么你什么都不做。这样,您的应用处理就可以根据需要对电池产生影响。

significantLocationChanges旨在减少影响,根据我的经验,它可以很好地完成它。另一种选择是使用区域监控,或者与。一起使用。

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

答案 1 :(得分:1)

当应用程序在后台时与应用程序暂停时获取位置更新是两种截然不同的方案。你将不得不以不同的方式处理它们。

时获取位置更新

A)应用程序在后台,请参阅:Background Location Services not working in iOS 7

B)应用暂停/终止,请参阅:How to Get Location Updates for iOS 7 and 8 Even when the App is Suspended

上述2场景的源代码可在GitHub上找到。