iOS 애플리케이션에서 n 분마다 백그라운드 위치 업데이트를 받으려면 어떻게합니까?


207

iOS 응용 프로그램에서 n 분마다 백그라운드 위치 업데이트를 얻는 방법을 찾고 있습니다. iOS 4.3을 사용하고 있으며이 솔루션은 손상되지 않은 iPhone에서 작동합니다.

다음 옵션을 시도 / 고려했습니다.

  • CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges: 이것은 구성된 속성에 따라 백그라운드에서 예상대로 작동하지만 n 분마다 위치를 강제로 업데이트 할 수는 없습니다.
  • NSTimer: 앱이 포 그라운드에서 실행될 때 작동하지만 백그라운드 작업을 위해 설계된 것 같지 않습니다.
  • 로컬 알림 : n 분마다 로컬 알림을 예약 할 수 있지만 사용자가 알림을 통해 앱을 시작하지 않고 현재 위치를 얻기 위해 일부 코드를 실행할 수는 없습니다. 이 접근 방식은 알림을 사용해야하는 것이 아니기 때문에 깨끗한 접근 방식이 아닌 것 같습니다.
  • UIApplication:beginBackgroundTaskWithExpirationHandler: 내가 아는 한, 이것은 "장기 실행"백그라운드 프로세스를 구현하는 대신 앱이 백그라운드로 이동 될 때 백그라운드에서 일부 작업 (시간 제한)을 완료하는 데 사용해야합니다.

정기적 인 백그라운드 위치 업데이트를 어떻게 구현할 수 있습니까?



유용한 후속 조치 : stackoverflow.com/questions/10235203/…
Lolo

1
iOS 7에서 작동하게하려는 경우 여기 에서이 솔루션을 시도해 볼 수 있습니다. stackoverflow.com/questions/18946881/… 궁금한 점이 있으면 mobileoop.com/background
Ricky

1
모든 결과가 정확합니다 (4 개의 글 머리 기호). 그렇다면 귀중한 사례와 일치하지 않는 귀중한 정보는 무엇입니까? 그리고 예, 일시 중단 모드 또는 실행 중이 아닐 때 n 분마다 업데이트 할 수있는 궁극적 인 방법은 없습니다.
LenArt

답변:


113

Apple 개발자 포럼의 도움으로 이것을 구현하는 솔루션을 찾았습니다.

  • 지정 location background mode
  • NSTimer와 함께 백그라운드에서 만들기UIApplication:beginBackgroundTaskWithExpirationHandler:
  • n이다 작은 것보다 UIApplication:backgroundTimeRemaining그것을 잘 작동합니다. 때 n이다 는이 location manager다시 전에 살해되는 백그라운드 작업을 피하기 위해 남아있는 시간이 없다 활성화 (장애인)해야합니다.

location은 세 가지 유형의 백그라운드 실행 유형 중 하나이기 때문에 작동합니다 .

참고 : 작동하지 않는 시뮬레이터에서 이것을 테스트하여 시간을 잃었습니다. 그러나 내 전화에서는 제대로 작동합니다.


24
포럼으로 연결되는 링크가 있습니까? 동일한 유형의 위치 매핑을 구현하려고하지만 작동하지 못했습니다. 또는 일부 샘플 코드는 크게 감사하겠습니다.
utahwithak

4
위치 관리자를 중지하고 시작한 경우 10 분 (최대 허용 시간) 후에 백그라운드 작업이 종료되지 않는 이유를 설명해 주시겠습니까? 일종의 의도 된 기능입니까? Apple SDK에서는 버그처럼 들립니다. 어떤 iOS 버전을 사용하고 있습니까?
saurabh

5
@all : 예, AppStore에서 앱을 사용할 수 있습니다. 모든 코드를 게시하지는 않겠습니다. 언급 된 모든 글 머리 기호는 명확하게 문서화 된 기능입니다. 특정 문제가있는 경우 시도한 사항과 잘못된 점을 설명하는 질문을 게시하십시오.
wjans

3
@ user836026 : 예, 이것이 배경 모드를 지정한다는 의미입니다. 위치 업데이트를 중지 한 후 앱이 종료되지 않도록 10 분 이내에 다시 시작해야합니다.
wjans

12
여기에서 논의되고있는 내용을 반영한 실제 코드를 보는 데 관심이있는 모든 사람은 stackoverflow.com/questions/10235203/…을
Lolo

55

아이폰 OS 8/9/10 5 분마다 다음을 수행 배경 위치 업데이트로 만들려면 :

  1. 프로젝트-> 기능-> 백그라운드 모드로 이동하여 위치 업데이트를 선택하십시오.

  2. 프로젝트-> 정보-> 빈 값 (또는 선택적으로 모든 텍스트)으로 NSLocationAlwaysUsageDescription 키를 추가하십시오.

  3. 앱이 백그라운드에있을 때 위치가 작동하도록하고 웹 서비스에 좌표를 보내거나 5 분마다 아무 작업을 수행하려면 아래 코드와 같이 구현하십시오.

백그라운드 작업이나 타이머를 사용하고 있지 않습니다. 내 앱을 백그라운드에서 실행하면서 몇 시간 동안 책상에 누워있는 iOS 8.1을 사용하는 기기 에서이 코드를 테스트했습니다. 장치가 잠겨 있고 코드가 항상 제대로 실행되고있었습니다.

@interface LocationManager () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSDate *lastTimestamp;

@end

@implementation LocationManager

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
        LocationManager *instance = sharedInstance;
        instance.locationManager = [CLLocationManager new];
        instance.locationManager.delegate = instance;
        instance.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // you can use kCLLocationAccuracyHundredMeters to get better battery life
        instance.locationManager.pausesLocationUpdatesAutomatically = NO; // this is important
    });

    return sharedInstance;
}

- (void)startUpdatingLocation
{
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];

    if (status == kCLAuthorizationStatusDenied)
    {
        NSLog(@"Location services are disabled in settings.");
    }
    else
    {
        // for iOS 8
        if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
        {
            [self.locationManager requestAlwaysAuthorization];
        }
        // for iOS 9
        if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        {
            [self.locationManager setAllowsBackgroundLocationUpdates:YES];
        }

        [self.locationManager startUpdatingLocation];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *mostRecentLocation = locations.lastObject;
    NSLog(@"Current location: %@ %@", @(mostRecentLocation.coordinate.latitude), @(mostRecentLocation.coordinate.longitude));

    NSDate *now = [NSDate date];
    NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0;

    if (!self.lastTimestamp || interval >= 5 * 60)
    {
        self.lastTimestamp = now;
        NSLog(@"Sending current location to web service.");
    }
}

@end

3
몇 시간 이상 작동합니까? 앱이 종료되지 않은 경우에도 한 시간 정도 지나면 앱이 백그라운드로 이동 한 후 기기에서 위치 업데이트 푸시를 중지합니다.
Myxtic

2
내 프로젝트에서 백그라운드 가져 오기가 비활성화되어 있습니다 (끄거나 켜도 상관 없습니다). 그러나 위 예제가 제대로 작동하려면 pausesLocationUpdatesAutomatically를 NO로 설정해야합니다. 이전에 시스템에서 일시 중지 한 경우 다시 이동을 시작하면 자동으로 다시 시작되지 않습니다. 그렇기 때문에 위 예제에서이 속성을 NO로 설정했습니다.
Leszek Szary

1
당신이 옳다고 생각합니다. 이 문제에 대한 자세한 내용은 여기를 참조하십시오 : stackoverflow.com/q/17484352/1048331
Myxtic

2
@LeszekS는 배경에 대 한 아이폰 OS 9 지원을위한 코드 아래에 추가 할 필요가 - if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Fenil

2
이 작업의 편리함은 무엇입니까? 당신은 여전히 ​​높은 정확도를 유지함으로써 배터리를 소모하고 있습니다. 당신이하지 않는 유일한 것은 당신이 5 분 간격에 도달 할 때까지 이미받은 위치를 실제로 사용하지 않는 것입니다 ...
Honey

34

개발중인 응용 프로그램 에서이 작업을 수행했습니다. 앱이 백그라운드에있을 때 타이머가 작동하지 않지만 앱이 지속적으로 위치 업데이트를 수신하고 있습니다. 응용 프로그램이 백그라운드에있을 때 활성 실행 루프에서만 메소드를 호출 할 수 있다는 문서의 어딘가를 읽었습니다 (지금 찾을 수없는 것 같습니다. 내가 할 때 업데이트를 게시 할 것입니다). 앱 대리자는 bg에서도 활성 실행 루프를 가지고 있으므로이 작업을 수행하기 위해 직접 만들 필요가 없습니다. [올바른 설명인지 확실하지 않지만 내가 읽은 내용을 어떻게 이해했는지]

우선, 앱의 info.plist에 location키 의 객체를 추가하십시오 UIBackgroundModes. 이제 앱에서 위치 업데이트를 시작하면됩니다.

    CLLocationManager locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;//or whatever class you have for managing location
    [locationManager startUpdatingLocation];

다음으로 -(void)didUpdateToLocation:(CLLocation*)location앱 델리게이트에서 위치 업데이트를 처리하는 메소드를 작성하십시오 . 그런 다음 위치 관리자를 'self'로 설정 했으므로 위치 관리자를 시작한 클래스에서 메소드 locationManager:didUpdateLocation:fromLocation를 구현하십시오 CLLocationManagerDelegate. 이 방법 내에서 위치 업데이트를 처리해야하는 시간 간격이 경과했는지 확인해야합니다. 매번 현재 시간을 저장하면됩니다. 해당 시간이 경과하면 앱 델리게이트에서 UpdateLocation 메소드를 호출하십시오.

NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *lastLocationUpdateTiemstamp;

int locationUpdateInterval = 300;//5 mins

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (userDefaults) {

        lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp];

        if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) {
            //NSLog(@"New Location: %@", newLocation);
            [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation];
            [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp];
        }
    }
}

앱이 백그라운드에있는 경우에도 5 분마다 메소드를 호출합니다. Imp : 위치 데이터의 정확도가 중요하지 않은 경우이 구현은 배터리를 소모합니다.[locationManager startMonitoringSignificantLocationChanges]

이것을 앱에 추가하기 전에 위치 인식 프로그래밍 안내서 를 읽으십시오


3
그렇게하면 위치 서비스가 지속적으로 활성화되고 (실제로 배터리 방전) 그렇게하고 싶지 않습니다. 나는 n 분마다 위치 서비스를 활성화하고 좋은 수정이있을 때 즉시 비활성화하고 싶습니다 (제 질문에 명확하게 설명하지 않았다는 것을 알았습니다). 내가 설명한 솔루션에서이 동작을 달성 할 수 있습니다.
wjans 2012 년

3
위치 관리자 정확도를 1km로 설정할 수 있습니다. 이렇게하면 배터리가 거의 손상되지 않습니다. 5 분 후 정확도를 1m로 설정했습니다. 만족스러운 위치에 도달하면 (일반적으로 5 초 후) 정확도를 1km로 다시 설정하십시오.
knagode

knagode, 배터리 소모 문제에 대한 제안 솔루션을 시도했지만 N 분 후에 정확도가 높아진 후에도 locationManager : didUpdateLocations 메소드가 다시 호출되지 않습니다. ... N 분 후, didUpdateLocations 방법,하지만 백그라운드 모드에서 작동하지 않습니다 : 내가 대신 증가와 감소의 정확도, 그것은을 locationManager을 위임 성공적이라고, startUpdating 및 stopUpdating을 시도
Hardik Darji에게

문서의 링크에 관해서. 참조 여기 : "대리자 개체의 방법은 당신이 해당 위치 서비스를 시작하는 스레드에서 호출되는 하나의 응용 프로그램의 메인 쓰레드에서 발견 된 같은 스레드 자체가 활성 실행 루프를 가지고 있어야합니다.."
Honey

24

이제 iOS6가 영원히 실행되는 위치 서비스를 얻는 가장 좋은 방법은 다음과 같습니다.

- (void)applicationWillResignActive:(UIApplication *)application
{
/*
 Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
 */

NSLog(@"to background");

app.isInBackground = TRUE;

UIApplication *app = [UIApplication sharedApplication];

// Request permission to run in the background. Provide an
// expiration handler in case the task runs long.
NSAssert(bgTask == UIBackgroundTaskInvalid, nil);

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    // Synchronize the cleanup call on the main thread in case
    // the task actually finishes at around the same time.
    dispatch_async(dispatch_get_main_queue(), ^{

        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
}];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

    locationManager.distanceFilter = 100;
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    [locationManager startMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];

    NSLog(@"App staus: applicationDidEnterBackground");
    // Synchronize the cleanup call on the main thread in case
    // the expiration handler is fired at the same time.
    dispatch_async(dispatch_get_main_queue(), ^{
        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
});

NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);

}

다음과 같이 테스트했습니다.

앱을 시작하고 백그라운드로 가서 몇 분 정도 차 안에서 움직입니다. 그런 다음 1 시간 동안 집에 가서 다시 앱을 열지 않고 다시 움직이기 시작합니다. 위치가 다시 시작되었습니다. 그런 다음 2 시간 동안 멈추었다가 다시 시작했습니다. 다 괜찮아 ...

iOS6의 새로운 위치 서비스 사용을 잊지 마십시오

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{   
    CLLocation *loc = [locations lastObject];

    // Lat/Lon
    float latitudeMe = loc.coordinate.latitude;
    float longitudeMe = loc.coordinate.longitude;
}

1
앱이 충돌하거나 종료되면 시스템이 다시 시작되지 않습니다.
Ken

1
더 읽기 쉬운 코드를 위해 [locations lastObject]; [locations objectAtIndex : [locations count]-1] 대신
axello

당신의 방법은 ios6에만 있습니까?
pengwang

이것을 사용해야합니까? 클래스의 viewDidLoad에 위치 관리자 코드가 있다고 생각하고 plist 파일에 앱이 위치 업데이트에 등록하는 배경 키가 충분해야한다고 생각 했습니까? 도와주세요.
nithinreddy

그렇습니다. 매력적인 매력처럼 작동하지만 iOS가 그 기간 후에 긴 스레드를 죽이기 때문에 10 분 후에 작동이 중단됩니다. 이러한 서비스를 영원히 시작하려면 내 솔루션이 완벽합니다. 나는 이틀 전에 몇 가지 테스트를 한 결과 매시간 6 % 배터리를 소모합니다. [startUpdatingLocation을 locationManager이 대신에 17 %를 사용한다 드레인
알레한드로 Luengo

13

악몽을 겪고있는 다른 사람에게 이것을 알아보십시오. 간단한 해결책이 있습니다.

  1. raywenderlich.com 에서이 예제를 보십시오 -> 샘플 코드가 있습니다.이 코드는 완벽하게 작동하지만 불행히도 백그라운드 위치에는 타이머가 없습니다. 이것은 무한정 실행됩니다.
  2. 다음을 사용하여 타이머를 추가하십시오.

    -(void)applicationDidEnterBackground {
    [self.locationManager stopUpdatingLocation];
    
    UIApplication*    app = [UIApplication sharedApplication];
    
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    
     self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
    
    }
  3. info.plist에 "위치 업데이트를위한 앱 레지스터"를 추가하는 것을 잊지 마십시오.


3 분 이상 위치를 확보합니까?
SleepNot

기능-> 백그라운드 모드에서 위치를 설정해야합니다.
Sergio Andreotti

작동하지 않습니다 !! ? iOS 8과 iOS 10에서 확인했습니다
Kirti

틀 렸으면 말해줘. 읽은 내용에 따라 locationManager를 한 번만 시작하십시오. 그 후 모든 간격이 중복됩니다. 벌써 시작된 이래
Honey

작동하지만 170 초 후에 중지됩니다. 난 시간 제한을위한 백그라운드에서 내 작업을 실행하려면
anshuman burmman

8

내가 사용하는 것은 다음과 같습니다.

import Foundation
import CoreLocation
import UIKit

class BackgroundLocationManager :NSObject, CLLocationManagerDelegate {

    static let instance = BackgroundLocationManager()
    static let BACKGROUND_TIMER = 150.0 // restart location manager every 150 seconds
    static let UPDATE_SERVER_INTERVAL = 60 * 60 // 1 hour - once every 1 hour send location to server

    let locationManager = CLLocationManager()
    var timer:NSTimer?
    var currentBgTaskId : UIBackgroundTaskIdentifier?
    var lastLocationDate : NSDate = NSDate()

    private override init(){
        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManager.activityType = .Other;
        locationManager.distanceFilter = kCLDistanceFilterNone;
        if #available(iOS 9, *){
            locationManager.allowsBackgroundLocationUpdates = true
        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.applicationEnterBackground), name: UIApplicationDidEnterBackgroundNotification, object: nil)
    }

    func applicationEnterBackground(){
        FileLogger.log("applicationEnterBackground")
        start()
    }

    func start(){
        if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        } else {
                locationManager.requestAlwaysAuthorization()
        }
    }
    func restart (){
        timer?.invalidate()
        timer = nil
        start()
    }

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        switch status {
        case CLAuthorizationStatus.Restricted:
            //log("Restricted Access to location")
        case CLAuthorizationStatus.Denied:
            //log("User denied access to location")
        case CLAuthorizationStatus.NotDetermined:
            //log("Status not determined")
        default:
            //log("startUpdatintLocation")
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        }
    }
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        if(timer==nil){
            // The locations array is sorted in chronologically ascending order, so the
            // last element is the most recent
            guard let location = locations.last else {return}

            beginNewBackgroundTask()
            locationManager.stopUpdatingLocation()
            let now = NSDate()
            if(isItTime(now)){
                //TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now)
            }
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        CrashReporter.recordError(error)

        beginNewBackgroundTask()
        locationManager.stopUpdatingLocation()
    }

    func isItTime(now:NSDate) -> Bool {
        let timePast = now.timeIntervalSinceDate(lastLocationDate)
        let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL
        return intervalExceeded;
    }

    func sendLocationToServer(location:CLLocation, now:NSDate){
        //TODO
    }

    func beginNewBackgroundTask(){
        var previousTaskId = currentBgTaskId;
        currentBgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
            FileLogger.log("task expired: ")
        })
        if let taskId = previousTaskId{
            UIApplication.sharedApplication().endBackgroundTask(taskId)
            previousTaskId = UIBackgroundTaskInvalid
        }

        timer = NSTimer.scheduledTimerWithTimeInterval(BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false)
    }
}

AppDelegate에서 다음과 같이 추적을 시작합니다.

BackgroundLocationManager.instance.start()

감사. 우리 프로젝트는 사용자 위치를 추적하고 백그라운드에서 PubNub 이벤트를 보내야하며 솔루션이 실제로 잘 작동합니다.
user921509

나는 캔 전화 sendLocationToServer 방법은 서버에 사용자의 위치를 전송하는 하이 Hmitkov,
AmanGupta007

@ AmanGupta007 funLocation locationManager (manager : didUpdateLocations :)에서 sendLocationToServer를 호출 할 수 있습니다. 코드에서 // TODO 주석을 확인하십시오.
hmitkov 2016 년

@hmitkov 앱이 백그라운드에있는 동안이 위치 서비스를 시작 및 중지 할 수 있습니까? 예를 들어, 푸시 알림에서 위치 서비스를 시작하면 위도 / 경도를 잡고 웹 서비스로 보낸 다음 위치 업데이트를 중지합니다. 'content-available'= 1이 푸시 본문에 포함될 때마다이 작업을 수행하십시오.
DookieMan

1
이 코드를 시도했지만 iOS11에서 작동하지 않는 것 같습니다. (다른 버전에서는 테스트하지 않았습니다.)
Tom

6

불행히도, 당신의 모든 가정은 정확 해 보입니다. 나는 이것을 할 방법이 없다고 생각합니다. 배터리 수명을 절약하기 위해 iPhone의 위치 서비스는 움직임을 기반으로합니다. 휴대 전화가 한 곳에 있으면 위치 서비스가 보이지 않습니다.

CLLocationManager단지 호출 locationManager:didUpdateToLocation:fromLocation:전화가 세 개의 위치 서비스 중 하나 (기지국, GPS, 와이파이)의 변화를 감지하는 경우에만 발생 위치 업데이트를받을 때.

추가 솔루션을 알리는 데 도움이되는 몇 가지 다른 사항 :

  • 서비스를 시작 및 중지하면 didUpdateToLocation대리자 메서드가 호출되지만 newLocation이전 타임 스탬프가있을 수 있습니다.

  • 지역 모니터링이 도움이 될 수 있습니다

  • 백그라운드에서 실행하는 경우 Apple에서 승인 한 "전체"LocationServices 지원을 받기가 어려울 수 있습니다. 필자가 본 바에 startMonitoringSignificantLocationChanges따르면 백그라운드 위치 지원이 필요한 앱을위한 저전력 대안으로 특별히 설계되었으며 앱에서 절대적으로 필요하지 않는 한 개발자가이 기능을 사용하도록 권장합니다.

행운을 빕니다!

업데이트 :이 생각은 지금 구식 일 수 있습니다. 사람들이 위의 @ wjans 답변으로 성공한 것처럼 보입니다.


1
AppStore에는 백그라운드에서 위치 업데이트를 얻을 수있는 앱 (예 : "My Locus")이 있습니다. 위치 서비스를 활성 상태로 유지하지는 않지만 정의 된 간격에 따라 곧 활성화됩니다. 그들은 이것을 어떻게합니까?
wjans

2
설명하는 상황에서 앱은 startMonitoringSignificantLocationChanges 접근 방식을 사용하고있을 가능성이 높습니다. 여기에서 휴대 전화가 위치 업데이트를 수신하면 일시적으로 '깨어나'지만 백그라운드에서이 서비스를 '핑'하도록 설정할 수있는 간격은 없습니다. 전화가 이동하면 (또는 셀룰러에서 GPS 또는 Wifi로 전환) 업데이트가 트리거됩니다. 이 주제에 관한 Stanford iTunes U 강의는 저에게 정말 도움이
되었으면합니다

2
포인터의 Thx 그러나 여전히 앱이 무엇을하는지 이해하지 못합니다. 휴대 전화가 책상 위에 있어도 전혀 움직이지 않더라도 위치 서비스가 10 분마다 (정확하게) 트리거되는 것을 볼 수 있습니다. 올바르게 이해하면 startMonitoringSignificantLocationChanges해당 경우 업데이트를 제공하지 않습니다.
wjans

1
@ wjans 휴대 전화 배터리 소비는 어떻습니까? Mylocus 앱으로 인해 배터리가 빨리 소모되는 것을 보셨습니까?
user836026

6

위치 서비스를 사용하여 앱을 작성했습니다. 앱은 10 초마다 위치를 보내야합니다. 그리고 그것은 아주 잘 작동했습니다.

Apple의 문서에 따라 " allowDeferredLocationUpdatesUntilTraveled : timeout "메소드를 사용하십시오 .

내가 한 일은 :

필수 : 업데이트 위치를위한 백그라운드 모드를 등록하십시오.

1. 생성 LocationMangerstartUpdatingLocation함께, 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: 콜백을 사용 하여 앱이 정상적으로 위치를 업데이트합니다 .

-(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 앱이 백그라운드 / 전경 모드간에 전환 할 때마다 매개 변수를 재설정해야한다고 생각 합니다.


@이 배터리 이상 wjans의 설명 된 솔루션 중 장치 배터리를 절약하는 것이 좋습니까?
Yash December

2
나는 당신이 언급 한 두 가지 해결책을 모두 시도했지만 @wjans의 것이 조금 더 배터리 절약이라는 것을 알았습니다. 그러나 iOS 8이 출시 된 후에는 솔루션이 더 이상 제대로 작동하지 않는 것 같습니다. 자세한 내용 : 대부분의 경우 앱은 백그라운드 모드에서 오래 살 수 없습니다.
samthui7

@ samthui7 왜 pausesLocationUpdatesAutomatically = false를 설정합니까?
CedricSoubrie

내 응용 프로그램의 요구 사항은 10 초마다 userLocation을 계속 보내야하지만 pausesLocationUpdatesAutomatically = true위치 변경이없는 경우 위치 관리자에게 업데이트를 일시 중지하도록 지시합니다 ( Apple의 doc ). 어쨌든, 나는 location manager pauses updates아직 : D 의 경우를 명시 적으로 테스트하지 않았습니다 .
samthui7

@CedricSoubrie : 설정 pausesLocationUpdatesAutomatically = true하면 앱이 위치 업데이트를 중지합니다.
samthui7

5
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [self.locationManager setAllowsBackgroundLocationUpdates:YES];
}

iOS 9 이후 백그라운드 위치 추적에 필요합니다.


1
이것은 나의 하루를 구했다! iOS9 기기와 함께 iOS8 배포 대상 사용
Yaro

4

xs2bush의 간격을 얻는 방법 (을 사용하여 timeIntervalSinceDate)을 사용 하고 조금 확장했습니다. 필요한 필수 정확도를 얻고 GPS 라디오를 필요 이상으로 유지하여 배터리를 소모하지 않았는지 확인하고 싶었습니다.

다음 설정으로 위치를 계속 실행합니다.

locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locationManager.distanceFilter = 5;

이는 배터리 소모량이 상대적으로 적습니다. 다음에 주기적으로 위치 정보를 읽을 준비가되면 먼저 위치가 원하는 정확도 내에 있는지 확인한 다음 해당 위치를 사용하는지 확인합니다. 그렇지 않은 경우 다음과 같이 정확도를 높입니다.

locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter = 0;

내 위치를 찾은 다음 위치를 찾으면 배터리의 소모를 최소화하기 위해 정확도를 다시 낮추십시오. 나는 이것의 완전한 작동 샘플을 작성했으며 또한 위치 데이터를 수집하고 데이터베이스에 저장하고 gps 데이터를 실시간으로 보거나 이전에 저장된 경로를 검색하고 볼 수 있도록 서버 측 코드의 소스를 작성했습니다. iOS, Android, Windows Phone 및 Java 클라이언트가 있습니다. 모든 고객은 기본적으로 작성되었으며 모두 백그라운드에서 올바르게 작동합니다. 이 프로젝트는 MIT 라이센스가 있습니다.

iOS 프로젝트는 iOS 7의 기본 SDK를 사용하여 iOS 6을 대상으로합니다 . 여기 에서 코드를 얻을 수 있습니다 .

github에 문제가 있으면 문제를 제기하십시오. 감사.


난 당신의 솔루션을 시도했지만 작동하지 않습니다 ... 응용 프로그램도 증가 정확도 후, 다음 배경에 갈 때, 응용 프로그램은 내 경우라고 didUpdateToLocation 방법을 gettign하지 않습니다
Hardik Darji

@HardikDarji 중요한 질문입니다. 이사하고 있습니까? 그렇지 않으면 위치 업데이트가 중지 될 수 있습니다. 산책이나 드라이브를 위해 휴대 전화를 꺼내고 문제가 해결되는지 확인하십시오.
nickfox 2014 년

빠른 답변 감사합니다. 그러나 휴대 전화가 움직이지 않든 상관없이 2 분마다 위치 업데이트를 원합니다. 이 시나리오에서는 didUpdateToLocation 메소드가 호출되지 않습니다. 나는 여기를 찾고있다 : 어떻게 n 분마다 위치 업데이트를 받습니까?
Hardik Darji 2014 년

timeIntervalInSeconds를 120으로 설정하고 다음 줄의 주석을 해제하십시오. locationManager.pausesLocationUpdatesAutomatically = NO;
nickfox

1
위의 의견에 게시 한 솔루션으로 배터리 수명이 단축됩니까? 아니면 여전히 최적화하고 있습니까?
samfr

2

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


2

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

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

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


목표 c에 이와 같은 것이 있습니까?
Moxarth

1

iOS 9 및 watchOS 2.0에는 CLLocationManager에 새로운 위치 인 CLLocationManager : requestLocation ()을 사용하여 현재 위치를 요청할 수 있습니다. 이것은 즉시 완료된 다음 CLLocationManager 대리자에게 위치를 반환합니다.

NSTimer를 사용하여이 메소드로 1 분마다 위치를 요청할 수 있으며 startUpdatingLocation 및 stopUpdatingLocation 메소드로 작업 할 필요가 없습니다.

그러나 마지막 위치에서 X 미터의 변화에 ​​따라 위치를 캡처하려면 CLLocationManger의 distanceFilter 속성을 X 호출 startUpdatingLocation ()으로 설정하십시오.


-1

다음에 기반한 Swift 솔루션이 첨부되었습니다.

App registers for location updatesinfo.plist에서 정의

locationManager를 항상 실행 상태로 유지

스위치 kCLLocationAccuracy사이 BestForNavigation(5 초는 위치를 얻을)와 ThreeKilometers피할 배터리 배수에 대기 시간의 나머지 부분에 대한

이 예는 Foreground에서 1 분마다 및 Background에서 15 분마다 위치를 업데이트합니다.

이 예제는 iOS 7 장치에서 실행되는 Xcode 6 Beta 6에서 잘 작동합니다.

앱 위임에서 (mapView는 mapView 컨트롤러를 가리키는 선택적)

func applicationDidBecomeActive(application: UIApplication!) {
    if appLaunched! == false { // Reference to mapView used to limit one location update per timer cycle
        appLaunched = true
        var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        var window = appDelegate.window
        var tabBar = window?.rootViewController as UITabBarController
        var navCon = tabBar.viewControllers[0] as UINavigationController
        mapView = navCon.topViewController as? MapViewController
    }
    self.startInitialPeriodWithTimeInterval(60.0)
}

func applicationDidEnterBackground(application: UIApplication!) {
    self.startInitialPeriodWithTimeInterval(15 * 60.0)
}

func startInitialPeriodWithTimeInterval(timeInterval: NSTimeInterval) {
    timer?.invalidate() // reset timer
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getFirstLocationUpdate:"), userInfo: timeInterval, repeats: false)
}

func getFirstLocationUpdate(sender: NSTimer) {
    let timeInterval = sender.userInfo as Double
    timer?.invalidate()
    mapView?.canReportLocation = true
    timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("waitForTimer:"), userInfo: timeInterval, repeats: true)
}

func waitForTimer(sender: NSTimer) {
    let time = sender.userInfo as Double
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    finalTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getLocationUpdate"), userInfo: nil, repeats: false)
}

func getLocationUpdate() {
    finalTimer?.invalidate()
    mapView?.canReportLocation = true
}

mapView에서 (locationManager는 AppDelegate의 객체를 가리킴)

override func viewDidLoad() {
    super.viewDidLoad()
    var appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
    locationManager = appDelegate.locationManager!
    locationManager.delegate = self
    canReportLocation = true
}

  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        if canReportLocation! {
            canReportLocation = false
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
        } else {
            //println("Ignore location update")
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.