주기적인 iOS 백그라운드 위치 업데이트


91

높은 정확도와 낮은 빈도로 백그라운드 위치 업데이트가 필요한 응용 프로그램을 작성 중 입니다. 솔루션은 위치 관리자의 업데이트를 시작하고 즉시 종료되는 백그라운드 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];

}

현재 동작은 backgroundTimeRemaining180 초에서 0 (위치 로깅 중)으로 감소한 다음 만료 처리기가 실행되고 추가 위치 업데이트가 생성되지 않는 것입니다. 백그라운드에서주기적인 위치 업데이트를 무기한 수신하려면 위 코드를 어떻게 수정 합니까?

업데이트 : iOS 7을 대상으로하고 있으며 백그라운드 작업이 다르게 작동한다는 몇 가지 증거가있는 것 같습니다.

백그라운드 작업에서 iOS 7에서 위치 관리자 시작


목표로 삼고있는 iOS 버전은 언급하지 않습니다. 예를 들어 iOS 7에는 이전 제품과 다른 멀티 태스킹 시스템이 있습니다.
Jason Whitehorn

@JasonWhitehorn 좋은 지적입니다. 질문을 업데이트했습니다.
pcoving

2
@pcoving : 앱이 종료되거나 종료 된 경우에도 솔루션이 작동합니까?
Nirav

답변:


62

이것이 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 %로 감소했습니다.


4
전체 작동 예제로 질문을 업데이트 할 수 있습니까? 같은 것 : "업데이트 : 알아 냈어요. 여기 내 해결책이 있습니다 ..."
smholloway

@Virussmca 비슷한 성능으로 훨씬 더 강력한 이전 답변으로 되돌 렸습니다. 위치 업데이트를 모두 중지하면 경합 상태 (또는 기타 비 결정적 시나리오)가 트리거되는 것처럼 보입니다.
pcoving

이 방법은 예상대로 작동하지 않습니다. 1) distanceFilter 속성 값을 늘리면 gps가 사용자의 위치를 ​​계속 파악해야하기 때문에 배터리가 절약되지 않습니다. 2) iOS 7에서 백그라운드 시간은 연속적이지 않습니다. 3) 중요한 ChangeLocation 서비스를 고려할 수 있습니다. 4) iOS 7의 soution 외에도 UIBackgroundModes를 시작할 수 없습니다-배경에서 위치 ...
aMother

2
@aMother 1) 거리 필터를 늘리고 콜백을 처리하지 않아도 배터리가 많이 절약되지 않는다는 것을 알고 있습니다. 그러나 setDesiredAccuracy는 그렇습니다! 기본적으로 무료로 제공되는 기지국 정보로 돌아갑니다. 2) 비 연속적? 3) 높은 정확성이 필요하다고 굵게 표시했습니다. 중요한 위치 변경은이를 제공하지 않습니다. 4) 위치 서비스가 백그라운드에서 시작 / 중지되지 않습니다.
pcoving

2
나는 이것이 지금 오래된 게시물이라는 것을 알고 있지만이 트릭을 사용하는 내 응용 프로그램의 사용자는 iOS9로 업그레이드 한 이후 배터리 사용량이 크게 증가했습니다. 아직 조사하지 않았지만이 '속임수'가 더 이상 작동하지 않을 것 같습니까?
Gary Wright

45

위치 서비스를 사용하여 앱을 작성했는데 앱은 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의 매개 변수를 재설정해야한다고 생각합니다.


이것은 훌륭하게 작동하며 작년 WWDC에서 언급 한 것처럼 이것이 올바른 방법이라고 생각합니다 !! 게시물 주셔서 감사합니다
prasad1250 2014

@ samthui7 감사합니다.하지만 종료 후에도 위치를 가져와야합니다. 어떻게 될 수 있습니다. ??
Mohit Tomar

@ samthui7 ..이 질문을 참조하십시오 ... stackoverflow.com/questions/37338466/…
Suraj Sukale

2
@amar : iOS 10 베타에서도 확인했지만 여전히 작동합니다. startUpdatingLocation : allowsBackgroundLocationUpdates = YESrequestAlwaysAuthorization또는 전에 일부 코드를 추가해야합니다 requestWhenInUseAuthorization. 예 :`CLLocationManager * locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = 자기; locationManager.allowsBackgroundLocationUpdates = 예; [locationManager requestAlwaysAuthorization]; [locationManager startUpdatingLocation];`
samthui7

1
@Nirav 아니요. 제가 아는 한 Apple이 그렇게 할 수 있다고 생각하지 않습니다.
samthui7

38
  1. 당신이있는 경우 UIBackgroundModes에 당신의 plist에 location키 당신은 사용에 필요하지 않은 beginBackgroundTaskWithExpirationHandler방법. 그것은 중복입니다. 또한 잘못 사용하고 있지만 ( 여기 참조 ) plist가 설정 되었기 때문에 문제가됩니다.

  2. 함께 UIBackgroundModes locationPLIST의 응용 프로그램은 무기한 동안 만 같이 백그라운드에서 계속 실행됩니다 CLLocationManger실행됩니다. stopUpdatingLocation백그라운드에서 전화 하면 앱이 중지되고 다시 시작되지 않습니다.

    전화 beginBackgroundTaskWithExpirationHandler하기 직전에 전화를 걸고 전화 stopUpdatingLocation를 한 후 GPS가 중지 된 동안 백그라운드 상태를 유지하기 위해에게 전화를 startUpdatingLocation걸 수도 endBackgroundTask있지만, 시도해 본 적이 없습니다.

    또 다른 옵션 (내가 시도하지 않은)은 백그라운드에있는 동안 위치 관리자를 계속 실행하는 것입니다.하지만 정확한 위치를 얻으면 desiredAccuracy속성을 1000m 이상으로 변경 하여 GPS 칩이 꺼 지도록합니다 (배터리 절약을 위해). 그런 다음 10 분 후 다른 위치 업데이트가 필요하면 desiredAccuracy다시 100m로 변경하여 정확한 위치를 얻을 때까지 GPS를 켜고 반복합니다.

  3. startUpdatingLocation위치 관리자 를 호출 할 때 위치를 확보 할 시간을 주어야합니다. 즉시 전화해서는 안됩니다 stopUpdatingLocation. 최대 10 초 동안 또는 캐시되지 않은 고정밀 위치를 얻을 때까지 실행되도록합니다.

  4. 캐시 된 위치를 필터링하고 필요한 최소 정확도를 충족하는지 확인하는 위치의 정확도를 확인해야합니다 ( 여기 참조 ). 첫 번째 업데이트는 10 분 또는 10 일이 지난 것입니다. 첫 번째 정확도는 3000m 일 수 있습니다.

  5. 대신 중요한 위치 변경 API를 사용해보십시오. 중요한 변경 알림을 받으면 CLLocationManager몇 초 동안 시작 하여 정확한 위치를 얻을 수 있습니다. 확실하지 않습니다. 중요한 위치 변경 서비스를 사용한 적이 없습니다.


Apple CoreLocation참조 beginBackgroundTaskWithExpirationHandler는 백그라운드에서 위치 데이터를 처리 할 때 다음을 사용하도록 권장하는 것 같습니다 . "iOS 앱이 위치 데이터를 처리하는 데 더 많은 시간이 필요한 경우 UIApplication 클래스의 beginBackgroundTaskWithName : expirationHandler : 메서드를 사용하여 더 많은 백그라운드 실행 시간을 요청할 수 있습니다." - developer.apple.com/library/ios/documentation/UserExperience/...
eliocs

4
_locationManager.allowsBackgroundLocationUpdates = YES를 추가하는 것을 잊지 마십시오. iOS9 +를 들어, 다른 응용 프로그램은 180 초 후에 잠을로 이동합니다
kolyancz

@kolyancz 방금 iPhone 6+ 용 iOS 10.1.1에서 사용해 보았습니다. 잠자기 및 트리거에 약 17 분이 걸렸습니다 locationManagerDidPauseLocationUpdates. 나는 그 행동을 10 번 확인했다!
Honey

난 정말 당신이 왜 그것이 문제라고
Honey

10

위치 서비스를 시작하고 백그라운드 작업을 중지 할 때가되면 백그라운드 작업이 지연되고 중지되어야합니다 (1 초이면 충분 함). 그렇지 않으면 위치 서비스가 시작되지 않습니다. 또한 위치 서비스는 몇 초 (예 : 3 초) 동안 켜져 있어야합니다.

원하는 위치 정확도로 n 초 마다 백그라운드 위치 업데이트를받을 수 있는 cocoapod APScheduledLocationManager 가 있습니다 .

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

저장소에는 Swift 3로 작성된 예제 앱도 포함되어 있습니다.


1

startMonitoringSignificantLocationChanges:API를 사용해 보는 것은 어떻습니까? 확실히 적은 빈도로 발사되며 정확도는 상당히 좋습니다. 또한 다른 locationManagerAPI를 사용하는 것보다 훨씬 더 많은 이점이 있습니다.

이 API에 대한 더 많은 내용은 이미이 링크 에서 논의되었습니다.


1
이 접근법을 시도했습니다. 정확성 요구 사항을 위반합니다- 문서에서 : This interface delivers new events only when it detects changes to the device’s associated cell towers
pcoving

1

info.plist에 다음 키를 추가하여 애플리케이션에 위치 업데이트 모드를 추가해야합니다.

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

didUpdateToLocation메서드가 호출됩니다 (앱이 백그라운드에있는 경우에도). 이 메서드 호출을 기반으로 모든 작업을 수행 할 수 있습니다.


위치 업데이트 모드는 이미 info.plist에 있습니다. 앞서 언급했듯이 180 초의 백그라운드 타임 아웃까지 업데이트를 받고 있습니다.
pcoving

0

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
    }

}

0

애플리케이션이 백그라운드에있는 동안 표준 위치 서비스를 사용하려면 먼저 대상 설정의 기능 탭에서 백그라운드 모드를 켜고 위치 업데이트를 선택해야합니다.

또는 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를 설정해야합니다.

목표 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];

빠른

self.locationManager.delegate = self
if #available (iOS 8.0,*) {
    self.locationManager.requestAlwaysAuthorization()
}
if #available (iOS 9.0,*) {
    self.locationManager.allowsBackgroundLocationUpdates = true
}
self.locationManager.startUpdatingLocation()

참조 : https://medium.com/@javedmultani16/location-service-in-the-background-ios-942c89cd99ba


-2
locationManager.allowsBackgroundLocationUpdates = true

4
답변 을 편집 하고 이것이 문제를 해결하는 이유 / 방법에 대한 설명을 추가 할 수 있습니까?
barbsan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.