定期iOS后台位置更新

pco*_*ing 91 objective-c core-location ios background-task ios-background-mode

我正在编写一个需要高精度和低频率的背景位置更新的应用程序.该解决方案似乎是一个后台NSTimer任务,它启动位置管理器的更新,然后立即关闭.之前已经问过这个问题:

如何在iOS应用程序中每n分钟更新一次后台位置?

应用程序进入后台后每n分钟获取用户位置

iOS不是典型的后台位置跟踪计时器问题

iOS长时间运行的后台计时器,带有"位置"后台模式

基于位置跟踪的iOS全天候后台服务

但我还没有得到最起码的例子.在尝试了上述接受的答案的每一个排列后,我总结了一个起点.输入背景:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"ending background task");
        [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
        self.bgTask = UIBackgroundTaskInvalid;
    }];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
}
Run Code Online (Sandbox Code Playgroud)

和委托方法:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation {

    NSLog(@"%@", newLocation);

    NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
    [self.locationManager stopUpdatingLocation];

}
Run Code Online (Sandbox Code Playgroud)

当前行为是backgroundTimeRemaining从180秒减少到零(记录位置时),然后执行到期处理程序,不再生成进一步的位置更新.如何修改上述代码以便在后台无限期地接收定期位置更新

更新:我的目标是iOS 7,似乎有一些证据表明后台任务的行为有所不同:

从后台任务启动iOS 7中的位置管理器

pco*_*ing 61

这似乎stopUpdatingLocation是触发后台看门狗定时器的原因,所以我将其替换didUpdateLocation为:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[self.locationManager setDistanceFilter:99999];
Run Code Online (Sandbox Code Playgroud)

这似乎有效地关闭了GPS.NSTimer然后背景的选择器变为:

- (void) changeAccuracy {
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}
Run Code Online (Sandbox Code Playgroud)

我所做的就是定期切换精度以便每隔几分钟获得一个高精度坐标,并且因为locationManager没有停止,所以backgroundTimeRemaining保持其最大值.这样可以减少电池消耗,从每小时约10%(kCLLocationAccuracyBest背景恒定)到我的设备每小时约2%.

  • 你能用完整的工作实例更新你的问题吗?类似的事情:"更新:我明白了.这是我的解决方案......" (4认同)
  • @aMother 1)我意识到增加距离过滤器(而不是处理回调)不会节省太多电池.但是,setDesiredAccuracy呢!它依赖于基本上免费提供的蜂窝塔信息.2)非连续?3)我用粗体指定我需要高精度.重要的位置变化不提供此功能.4)位置服务没有从后台启动/停止. (2认同)
  • 我知道这是一个旧帖子,但是我的应用程序使用这个技巧的用户注意到自升级到iOS9后电池使用量显着增加.我还没有调查过,但我觉得这个'技巧'可能不再适用了吗? (2认同)

sam*_*ui7 45

我确实使用位置服务编写应用程序,应用程序必须每10秒发送一次位置.而且效果很好.

只需按照Apple的doc 使用" allowDeferredLocationUpdatesUntilTraveled:timeout "方法即可.

步骤如下:

必需:注册更新位置的后台模式.

1.创建LocationManger和startUpdatingLocation,精确度和filteredDistance,如你所愿:

-(void) initLocationManager    
{
    // Create the manager object
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
    _locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    _locationManager.desiredAccuracy = 45;
    _locationManager.distanceFilter = 100;
    // Once configured, the location manager must be "started".
    [_locationManager startUpdatingLocation];
}
Run Code Online (Sandbox Code Playgroud)

2.要在后台使用"allowDeferredLocationUpdatesUntilTraveled:timeout"方法永久保持app运行,当app移动到后台时,必须使用新参数重新启动updatesLocation,如下所示:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];
 }
Run Code Online (Sandbox Code Playgroud)

3.应用程序正常使用"locationManager:didUpdateLocations:"回调获取updatedLocations:

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//  store data
    CLLocation *newLocation = [locations lastObject];
    self.userLocation = newLocation;

   //tell the centralManager that you want to deferred this updatedLocation
    if (_isBackgroundMode && !_deferringUpdates)
    {
        _deferringUpdates = YES;
        [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];
    }
}
Run Code Online (Sandbox Code Playgroud)

4.但是,你应该在随后处理数据":didFinishDeferredUpdatesWithError:的LocationManager"回调你的目的

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 
}
Run Code Online (Sandbox Code Playgroud)

5. 注意:我认为每次app在background/forground模式之间切换时我们都应该重置LocationManager的参数.

  • @amar:我也检查了iOS 10 beta,它仍然有效.请注意,我们需要在startUpdatingLocation之前添加一些代码:`allowsBackgroundLocationUpdates = YES`和`requestAlwaysAuthorization`或`requestWhenInUseAuthorization`.例如:`CLLocationManager*locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.allowsBackgroundLocationUpdates = YES; [locationManager requestAlwaysAuthorization]; [locationManager startUpdatingLocation];` (2认同)

pro*_*rmr 36

  1. 如果你UIBackgroundModes的plist有location钥匙,那么你不需要使用beginBackgroundTaskWithExpirationHandler方法.那是多余的.你也错误地使用它(见这里),但是因为你的plist被设置了,所以没有实际意义.

  2. 随着UIBackgroundModes location在plist中的应用程序将继续无限期只只要在后台运行CLLocationManger正在运行.如果您stopUpdatingLocation在后台打电话,那么应用程序将停止并且不会再次启动.

    也许你可以在打电话beginBackgroundTaskWithExpirationHandler之前拨打电话stopUpdatingLocation,然后在打电话之后startUpdatingLocation你可以打电话endBackgroundTask给它,以便在GPS停止时让它保持背景,但我从来没有尝试过 - 这只是一个想法.

    另一个选项(我没有尝试过)是让位置管理器在后台运行但是一旦你得到一个准确的位置desiredAccuracy就把属性改成1000米或更高,以便让GPS芯片关闭(以节省电池电量).然后10分钟后,当您需要另一个位置更新时,将desiredAccuracy背面更改为100米以打开GPS,直到您获得准确的位置,重复.

  3. 当你打电话startUpdatingLocation给位置经理时,你必须给它时间来获得一个位置.你不应该立即打电话stopUpdatingLocation.我们让它运行最多10秒或直到我们得到一个非缓存的高精度位置.

  4. 您需要过滤掉缓存的位置并检查所获得位置的准确性,以确保它符合您所需的最低精度(请参阅此处).您获得的第一个更新可能是10分钟或10天.您获得的第一个准确度可能是3000米.

  5. 请考虑使用重要的位置更改API.一旦获得重要更改通知,您可以启动CLLocationManager几秒钟以获得高精度位置.我不确定,我从未使用过重要的位置变更服务.

  • 别忘了添加_locationManager.allowsBackgroundLocationUpdates = YES; 对于iOS9 +,否则应用程序将在180秒后进入睡眠状态 (4认同)

sas*_*ash 9

当需要启动位置服务并停止后台任务时,应该延迟后台任务(1秒应该足够).否则位置服务不会启动.位置服务也应保持开启几秒钟(例如3秒).

有一个cocoapod APScheduledLocationManager,它允许每n秒获得具有所需位置精度的背景位置更新.

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
Run Code Online (Sandbox Code Playgroud)

存储库还包含一个用Swift 3编写的示例应用程序.


归档时间:

查看次数:

92397 次

最近记录:

6 年,2 月 前