|
|
强健的土豆 · qtablewight中AttributeE ...· 1 年前 · |
|
|
安静的甘蔗 · Sqlite插入单引号和双引号,防止sql注 ...· 1 年前 · |
|
|
道上混的饭盒 · Notify Update· 2 年前 · |
|
|
憨厚的麻辣香锅 · java 加了saveAndFlush ...· 2 年前 · |
|
|
开朗的烤土司 · ubuntu上mitmproxy通过透明代理 ...· 2 年前 · |
我正在写一个应用程序,需要与 高精度和低频率的 后台位置更新。解决方案似乎是一个后台NSTimer任务,它启动位置管理器的更新,然后立即关闭。这个问题以前已经问过了:
How do I get a background location update every n minutes in my iOS application?
Getting user location every n minutes after app goes to background
iOS Not the typical background location tracking timer issue
iOS long-running background timer with "location" background mode
iOS full-time background-service based on location tracking
但是我还没有得到一个可以正常工作的 最小示例 。在尝试了上述公认答案的每一种排列之后,我将一个起点放在一起。进入背景:
- (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秒递减到零(在记录位置时),然后执行过期处理程序,并且不会生成进一步的位置更新。如何修改上面的代码,以便在后台无限期地接收
定期位置更新
更新 :我的目标是iOS 7,似乎有一些证据表明后台任务的行为有所不同:
用
startMonitoringSignificantLocationChanges:
应用编程接口试试怎么样?它的触发频率肯定很低,而且准确度也相当好。此外,与使用其他
locationManager
应用编程接口相比,它具有更多的优势。
关于这个API的更多内容已经在这个 link 上讨论过了。
您需要在您的应用程序中添加位置更新模式,方法是在info.plist中添加以下键。
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
将调用
didUpdateToLocation
方法(即使您的应用程序在后台)。您可以根据此方法调用执行任何操作
UIBackgroundModes
和
location
键,那么你就不需要使用
beginBackgroundTaskWithExpirationHandler
方法。这是多余的。你也没有正确地使用它(参见
here
),但这是没有意义的,因为你的plist已经设置好了。在plist中有
UIBackgroundModes location
的
CLLocationManger
运行的时候,应用程序才会无限期地在后台运行。如果你在后台调用
stopUpdatingLocation
,那么应用程序将会停止并且不会再次启动。
也许你可以在调用
stopUpdatingLocation
之前调用
beginBackgroundTaskWithExpirationHandler
,然后在调用
startUpdatingLocation
之后,你可以调用
endBackgroundTask
来在GPS停止时保持它的后台,但我从来没有尝试过--这只是一个想法。
另一个选择(我还没有尝试过)是在后台保持位置管理器运行,但是一旦你得到一个准确的位置,将
desiredAccuracy
属性更改为1000m或更高,以允许关闭GPS芯片(以节省电池)。然后10分钟后,当你需要再次更新位置时,将
desiredAccuracy
调回100m以打开定位系统,直到你得到准确的位置,重复一次。
startUpdatingLocation
时,你必须给它时间来获得一个位置。您不应该立即调用
stopUpdatingLocation
。我们让它运行最多10秒,或者直到我们得到一个非缓存的高精度location.
CLLocationManager
几秒钟来获得一个高精度的位置。我不确定,我从来没有使用过重要的位置改变服务。
似乎是
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%。
我写了一个使用定位服务的应用程序,应用程序必须每10秒发送一次位置。它运行得非常好。
只需使用" allowDeferredLocationUpdatesUntilTraveled:timeout “方法,遵循苹果的文档。
具体步骤如下:
需要 :更新位置的 注册后台模式。
1. 创建LocationManger和startUpdatingLocation,并根据需要使用accuracy和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];
}
2. 为了让后台使用"allowDeferredLocationUpdatesUntilTraveled:timeout“方法的应用永远运行,必须在应用移到后台时使用新参数重启updatingLocation,如下所示:
- (void)applicationWillResignActive:(UIApplication *)application {
_isBackgroundMode = YES;
[_locationManager stopUpdatingLocation];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[_locationManager setDistanceFilter:kCLDistanceFilterNone];
_locationManager.pausesLocationUpdatesAutomatically = NO;
_locationManager.activityType = CLActivityTypeAutomotiveNavigation;
[_locationManager startUpdatingLocation];
}
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];
}
4.回调,但您应该根据自己的目的在 中处理数据
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {
_deferringUpdates = NO;
//do something
}
5. 注意: 我认为每次应用程序在后台/前台模式之间切换时,我们都应该重置LocationManager的参数。
当启动定位服务并停止后台任务时,后台任务需要延迟停止(1秒即可)。否则定位服务将无法启动。此外,位置服务应该保持打开几秒钟(例如3秒)。
有一个cocoapod APScheduledLocationManager ,它允许每隔n秒获得一次后台位置更新,并获得所需的位置精度。
let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
该存储库还包含一个用Swift 3编写的示例应用程序。
在iOS 8之后,苹果在CoreLocation框架方面做了一些变化,相关的背景提取和更新。
1)苹果在应用中引入了获取位置更新的AlwaysAuthorization请求。
2)苹果在iOS中引入了从后台获取位置的backgroundLocationupdates。
要在后台获取位置,您需要在Xcode的功能中启用位置更新。
//
// ViewController.swift
// DemoStackLocation
// Created by iOS Test User on 02/01/18.
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
}
locationManager.allowsBackgroundLocationUpdates = true
要在应用程序处于后台时使用标准定位服务,您需要首先在Target设置的Capabilities选项卡中打开后台模式,然后选择location updates。
或者,将其直接添加到 Info.plist 。
<key>NSLocationAlwaysUsageDescription</key>
<string>I want to get your location Information in background</string>
<key>UIBackgroundModes</key>
<array><string>location</string> </array>
然后,您需要设置CLLocationManager
Objective C
//The Location Manager must have a strong reference to it.
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
//Request Always authorization (iOS8+)
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [_locationManager requestAlwaysAuthorization];
//Allow location updates in the background (iOS9+)
if ([_locationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) { _locationManager.allowsBackgroundLocationUpdates = YES;
[_locationManager startUpdatingLocation];
Swift
self.locationManager.delegate = self
if #available (iOS 8.0,*) {
|
|
道上混的饭盒 · Notify Update 2 年前 |