定期iOS背景位置更新




objective-c iphone (6)

我正在编写一个需要高精度和低频率的背景位置更新的应用程序。 解决方案似乎是一个后台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];
}

和委托方法:

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

    NSLog(@"%@", newLocation);

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

}

当前的行为是backgroundTimeRemaining从180秒递减到0(记录位置),然后执行到期处理程序,并且不会生成进一步的位置更新。 如何修改上述代码以便无限期地在后台定期获取位置更新

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

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


  1. 如果你的plist中有UIBackgroundModeslocation键,那么你不需要使用beginBackgroundTaskWithExpirationHandler方法。 这是多余的。 你也错误地使用它(见here ),但自从你的plist被设置后,这是没有意义的。

  2. 使用plist中的UIBackgroundModes location ,只要CLLocationManger正在运行,应用程序将继续无限期地在后台运行。 如果您在后台调用stopUpdatingLocation ,则应用程序将停止并且不会再次启动。

    也许你可以在调用stopUpdatingLocation之前调用stopUpdatingLocation ,然后在调用startUpdatingLocation ,可以调用endBackgroundTask以在GPS停止时保持其背景,但我从来没有尝试过 - 这只是一个想法。

    另一种选择(我没有尝试过)是让位置管理器在后台运行,但是一旦你得到一个准确的位置,将desiredAccuracy属性改为1000m或更高,以允许GPS芯片关闭(以节省电池) 。 然后10分钟后,当您需要更新位置信息时,将所需的准确度更改回100m以打开GPS,直到您获得准确的位置,然后重复。

  3. 当您在地点经理上致电startUpdatingLocation时,您必须给它时间来获得职位。 您不应该立即调用stopUpdatingLocation 。 我们让它运行最多10秒,或者直到我们获得非缓存的高精度位置。

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

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


在iOS 8之后,它们是由苹果公司对CoreLocation框架相关的背景获取和更新进行的一些更改。

1)Apple引入AlwaysAuthorization请求来获取应用程序中的位置更新。

2)Apple在iOS中引入backgroundLocationupdates以从后台获取位置。

要在后台获取位置,您需要在Xcode的功能中启用位置更新。

//
//  ViewController.swift
//  DemoStackLocation
//
//  Created by iOS Test User on 02/01/18.
//  Copyright © 2018 iOS Test User. All rights reserved.
//

import UIKit
import CoreLocation

class ViewController: UIViewController {

    var locationManager: CLLocationManager = CLLocationManager()
    override func viewDidLoad() {
        super.viewDidLoad()
        startLocationManager()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    internal func startLocationManager(){
        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.startUpdatingLocation()
    }

}

extension ViewController : CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
        let location = locations[0] as CLLocation
        print(location.coordinate.latitude) // prints user's latitude
        print(location.coordinate.longitude) //will print user's longitude
        print(location.speed) //will print user's speed
    }

}

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

有一个cocoapod APScheduledLocationManager ,允许每n秒钟获得所需的位置准确度的后台位置更新。

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

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


您需要在您的应用程序中添加位置更新模式,方法是在您的info.plist中添加以下密钥。

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

didUpdateToLocation方法将被调用(即使你的应用程序在后台)。 您可以根据此方法调用执行任何操作


看起来stopUpdatingLocation是触发后台看门狗定时器的,所以我用didUpdateLocation替换它:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[self.locationManager setDistanceFilter:99999];

这似乎有效地关闭了GPS。 后台NSTimer的选择器变成:

- (void) changeAccuracy {
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}

我所做的全部工作是定期切换精确度,以便每隔几分钟获得一次高精度坐标,并且由于locationManager尚未停止,因此backgroundTimeRemaining保持其最大值。 这样可以将电池消耗从每小时10%左右(在后台持续保持kCLLocationAccuracyBest )降低到我的设备每小时约2%。


该项目将在后台管理位置。

位置背景更新器

如果应用程序进入后台并且需要发送网络呼叫更新位置,将自动进行管理。







ios-background-mode