높은 정확도와 낮은 빈도로 백그라운드 위치 업데이트가 필요한 응용 프로그램을 작성 중 입니다. 솔루션은 위치 관리자의 업데이트를 시작하고 즉시 종료되는 백그라운드 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을 대상으로하고 있으며 백그라운드 작업이 다르게 작동한다는 몇 가지 증거가있는 것 같습니다.
답변
이것이 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 초마다 위치를 전송해야합니다. 그리고 그것은 아주 잘 작동했습니다.
Apple의 문서에 따라 ” allowDeferredLocationUpdatesUntilTraveled : timeout “메소드를 사용하십시오 .
단계는 다음과 같습니다.
필수 : 업데이트 위치에 대한 백그라운드 모드를 등록합니다.
1. 원하는대로 정확도와 filterDistance를 사용하여 LocationManger 및 startUpdatingLocation을 만듭니다.
-(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”메소드를 사용하여 앱을 계속 실행하려면 다음과 같이 앱이 백그라운드로 이동할 때 새 매개 변수로 updatesLocation을 다시 시작해야합니다.
- (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. 그러나 “locationManager : didFinishDeferredUpdatesWithError :”콜백에서 데이터를 처리해야합니다.
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {
_deferringUpdates = NO;
//do something
}
5. 참고 : 앱이 백그라운드 / 포 그라운드 모드간에 전환 될 때마다 LocationManager의 매개 변수를 재설정해야한다고 생각합니다.
답변
-
당신이있는 경우
UIBackgroundModes
에 당신의 plist에location
키 당신은 사용에 필요하지 않은beginBackgroundTaskWithExpirationHandler
방법. 그것은 중복입니다. 또한 잘못 사용하고 있지만 ( 여기 참조 ) plist가 설정 되었기 때문에 문제가됩니다. -
함께
UIBackgroundModes location
PLIST의 응용 프로그램은 무기한 동안 만 같이 백그라운드에서 계속 실행됩니다CLLocationManger
실행됩니다.stopUpdatingLocation
백그라운드에서 전화 하면 앱이 중지되고 다시 시작되지 않습니다.전화
beginBackgroundTaskWithExpirationHandler
하기 직전에 전화를 걸고 전화stopUpdatingLocation
를 한 후 GPS가 중지 된 동안 백그라운드 상태를 유지하기 위해에게 전화를startUpdatingLocation
걸 수도endBackgroundTask
있지만, 시도해 본 적이 없습니다.또 다른 옵션 (내가 시도하지 않은)은 백그라운드에있는 동안 위치 관리자를 계속 실행하는 것입니다.하지만 정확한 위치를 얻으면
desiredAccuracy
속성을 1000m 이상으로 변경 하여 GPS 칩이 꺼 지도록합니다 (배터리 절약을 위해). 그런 다음 10 분 후 다른 위치 업데이트가 필요하면desiredAccuracy
다시 100m로 변경하여 정확한 위치를 얻을 때까지 GPS를 켜고 반복합니다. -
startUpdatingLocation
위치 관리자 를 호출 할 때 위치를 확보 할 시간을 주어야합니다. 즉시 전화해서는 안됩니다stopUpdatingLocation
. 최대 10 초 동안 또는 캐시되지 않은 고정밀 위치를 얻을 때까지 실행되도록합니다. -
캐시 된 위치를 필터링하고 필요한 최소 정확도를 충족하는지 확인하는 위치의 정확도를 확인해야합니다 ( 여기 참조 ). 첫 번째 업데이트는 10 분 또는 10 일이 지난 것입니다. 첫 번째 정확도는 3000m 일 수 있습니다.
-
대신 중요한 위치 변경 API를 사용해보십시오. 중요한 변경 알림을 받으면
CLLocationManager
몇 초 동안 시작 하여 정확한 위치를 얻을 수 있습니다. 확실하지 않습니다. 중요한 위치 변경 서비스를 사용한 적이 없습니다.
답변
위치 서비스를 시작하고 백그라운드 작업을 중지 할 때가되면 백그라운드 작업이 지연되고 중지되어야합니다 (1 초이면 충분 함). 그렇지 않으면 위치 서비스가 시작되지 않습니다. 또한 위치 서비스는 몇 초 (예 : 3 초) 동안 켜져 있어야합니다.
원하는 위치 정확도로 n 초 마다 백그라운드 위치 업데이트를받을 수 있는 cocoapod APScheduledLocationManager 가 있습니다 .
let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
저장소에는 Swift 3로 작성된 예제 앱도 포함되어 있습니다.
답변
startMonitoringSignificantLocationChanges:
API를 사용해 보는 것은 어떻습니까? 확실히 적은 빈도로 발사되며 정확도는 상당히 좋습니다. 또한 다른 locationManager
API를 사용하는 것보다 훨씬 더 많은 이점이 있습니다.
이 API에 대한 더 많은 내용은 이미이 링크 에서 논의되었습니다.
답변
info.plist에 다음 키를 추가하여 애플리케이션에 위치 업데이트 모드를 추가해야합니다.
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
didUpdateToLocation
메서드가 호출됩니다 (앱이 백그라운드에있는 경우에도). 이 메서드 호출을 기반으로 모든 작업을 수행 할 수 있습니다.
답변
iOS 8 이후 CoreLocation 프레임 워크 관련 백그라운드 가져 오기 및 Apple의 업데이트가 몇 가지 변경되었습니다.
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
}
}