Periyodik iOS arka planda konum güncellemeleri


92

Yüksek doğruluk ve düşük sıklıkta arka planda konum güncellemeleri gerektiren bir uygulama yazıyorum . Çözüm, konum yöneticisinin güncellemelerini başlatan ve ardından hemen kapanan bir arka plan NSTimer görevi gibi görünüyor. Bu soru daha önce sorulmuştu:

İOS uygulamamda her n dakikada bir arka planda konum güncellemesi nasıl alabilirim?

Uygulama arka plana gittikten sonra her n dakikada bir kullanıcı konumu alınıyor

iOS Tipik arka planda konum izleme zamanlayıcı sorunu değil

"Konum" arka plan modu ile iOS uzun süreli arka plan zamanlayıcı

Konum izlemeye dayalı tam zamanlı iOS arka plan hizmeti

ama henüz asgari bir örnek alamadım . Yukarıda kabul edilen cevapların her permütasyonunu denedikten sonra, bir başlangıç ​​noktası oluşturdum. Arka plana girme:

- (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];
}

ve temsilci yöntemi:

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

    NSLog(@"%@", newLocation);

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

}

Geçerli davranış, backgroundTimeRemaining180 saniyeden sıfıra düşmesi (konum günlüğe kaydedilirken) ve ardından sona erme işleyicisinin yürütülmesi ve başka konum güncellemelerinin üretilmemesidir. Süresiz olarak arka planda periyodik konum güncellemelerini almak için yukarıdaki kodu nasıl değiştirebilirim ?

Güncelleme : iOS 7'yi hedefliyorum ve arka plan görevlerinin farklı davrandığına dair bazı kanıtlar var gibi görünüyor:

Arka plan görevinden iOS 7'de Konum Yöneticisi'ni başlatın


Hangi iOS sürümünü hedeflediğinizden bahsetmiyorsunuz. iOS 7 (örneğin), öncekinden farklı bir çoklu görev sistemine sahiptir.
Jason Whitehorn

@JasonWhitehorn İyi nokta. Soruyu güncelledim.
pcoving

2
@pcoving: Uygulama kapatılsa veya sonlandırılsa bile çözümünüz çalışacak mı?
Nirav

Yanıtlar:


62

Görünüşe göre stopUpdatingLocationarka plan bekçi köpeği zamanlayıcısını tetikleyen şey bu , bu yüzden onu şu şekilde değiştirdim didUpdateLocation:

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

GPS'i etkin bir şekilde kapattığı görülüyor. Arka plan için seçici şu NSTimerhale gelir:

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

Tek yaptığım, birkaç dakikada bir yüksek doğrulukta bir koordinat elde etmek için doğruluğu periyodik olarak değiştirmek ve locationManagerdurdurulmadığı backgroundTimeRemainingiçin maksimum değerinde kalıyor. Bu kCLLocationAccuracyBest, cihazımda pil tüketimini saatte ~% 10'dan ( arka planda sabit olarak) ~% 2'ye düşürdü .


4
Sorunuzu tam çalışma örneği ile güncelleyebilir misiniz? Şöyle bir şey: "GÜNCELLEME: Anladım. İşte benim çözümüm ..."
smholloway

@Virussmca Benzer performansla çok daha sağlam olan önceki bir yanıta döndüm. Konum güncellemelerinin tamamen durdurulması bir yarış koşulunu (veya belirleyici olmayan başka bir senaryoyu) tetikliyor gibi görünüyor.
pcoving

Bu yaklaşım beklediğiniz gibi çalışmayacaktır: 1) distanceFilter özelliğinin değerini artırmak pil tasarrufu sağlamaz çünkü gps hala konumunuzu bulmaya devam etmelidir. 2) iOS 7'de arka plan süresi bitişik değildir. 3) ÖnemliChangeLocation hizmetlerini hesaba katabilirsiniz. 4) iOS 7'deki kaynağınız dışında, UIBackgroundModes'u başlatamazsınız - arka plandan konum ...
aMother

2
@aMother 1) Mesafe filtresini artırmanın (ve geri aramaları işlememenin) pil tasarrufu sağlamadığının farkındayım. Ancak setDesiredAccuracy yapar! Temelde ücretsiz olarak gelen baz istasyonu bilgilerine geri dönüyor. 2) Bitişik değil mi? 3) Yüksek doğruluğa ihtiyacım olduğunu kalın olarak belirttim. Önemli konum değişiklikleri bunu sağlamaz. 4) Konum hizmetleri arka planda başlatılmıyor / durdurulmuyor.
pcoving

2
Bunun artık eski bir gönderi olduğunu biliyorum, ancak uygulamamın bu numarayı kullanan kullanıcıları, iOS9'a yükselttikten sonra pil kullanımında önemli bir artış olduğunu fark ettiler. Henüz araştırmadım, ama bu 'numara'nın artık işe yaramayacağına dair bir his var mı?
Gary Wright

45

Konum hizmetlerini kullanarak bir uygulama yazdım, uygulama her 10 saniyede bir konum göndermeli. Ve çok iyi çalıştı.

Apple'ın belgesine göre " allowDeferredLocationUpdatesUntilTraveled: timeout " yöntemini kullanmanız yeterlidir .

Adımlar aşağıdaki gibidir:

Gerekli: Güncelleme Konumu için arka plan modunu kaydedin.

1. İstediğiniz gibi doğruluk ve filtrelenmişDistance ile LocationManger ve startUpdatingLocation oluşturun:

-(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. Arka planda "allowDeferredLocationUpdatesUntilTraveled: timeout" yöntemini kullanarak uygulamanın sonsuza kadar çalışmasını sağlamak için, uygulama arka plana taşındığında updateLocation'ı yeni parametre ile yeniden başlatmanız gerekir, örneğin:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];
 }

3. Uygulama "locationManager: didUpdateLocations:" geri arama ile normal şekilde güncellenen Konumları alır:

-(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. Ancak verileri amacınız için "locationManager: didFinishDeferredUpdatesWithError:" geri aramasında işlemelisiniz

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 
}

5. NOT: Uygulama arka plan / zemin modu arasında her geçiş yaptığında LocationManager parametrelerini sıfırlamamız gerektiğini düşünüyorum.


Bu harika çalışıyor ve geçen yıl WWDC'de belirtildiği gibi bunu yapmanın doğru yolu olduğunu düşünüyorum !!
Gönderi

@ samthui7 teşekkürler, bu işe yarıyor, ancak sonlandırmadan sonra da konum almam gerekiyor. nasıl olabilir.??
Mohit Tomar

@ samthui7 .. lütfen bu sıraya bakın ... stackoverflow.com/questions/37338466/…
Suraj Sukale

2
@amar: iOS 10 beta'yı da kontrol ettim, hala çalışıyor. StartUpdatingLocation: allowsBackgroundLocationUpdates = YESve requestAlwaysAuthorizationveya öncesinde bazı kodlar eklememiz gerektiğini unutmayın requestWhenInUseAuthorization. Örneğin: `CLLocationManager * locationManager = [[CLLocationManager ayırma] init]; locationManager.delegate = self; locationManager.allowsBackgroundLocationUpdates = YES; [locationManager requestAlwaysAuthorization]; [locationManager startUpdatingLocation]; `
samthui7

1
@Nirav Hayır. Bildiğim kadarıyla Apple'ın bunu yapmamıza izin vereceğini sanmıyorum.
samthui7

39
  1. Anahtarlı UIBackgroundModesplistinizde varsa, metodu locationkullanmanıza gerek yoktur beginBackgroundTaskWithExpirationHandler. Bu gereksizdir. Ayrıca yanlış kullanıyorsunuz ( buraya bakın ) ama bu, plistiniz ayarlandığından beri tartışmalı.

  2. İle UIBackgroundModes locationplist uygulama süresiz sadece sürece arka planda çalışmaya devam edecektir CLLocationMangerçalışıyor. stopUpdatingLocationArka plandayken ararsanız , uygulama durur ve tekrar başlamaz.

    Belki aramadan beginBackgroundTaskWithExpirationHandlerhemen önce arayabilirsin stopUpdatingLocationve sonra aradıktan sonra GPS dururken arka planda kalması için telefonunu startUpdatingLocationarayabilirsin endBackgroundTask, ama bunu hiç denemedim - bu sadece bir fikir.

    Başka bir seçenek (denemediğim) arka planda konum yöneticisini çalışır durumda tutmaktır, ancak doğru bir konum elde desiredAccuracyettiğinizde GPS çipinin kapanmasına izin vermek için (pilden tasarruf etmek için) özelliği 1000 m veya daha yükseğe değiştirin. 10 dakika sonra başka bir konum güncellemesine ihtiyaç duyduğunuzda, desiredAccuracydoğru bir konum elde edene kadar GPS'i açmak için geri 100 metreye getirin, tekrarlayın.

  3. Aradığınızda startUpdatingLocationkonum yöneticisi üzerinde bunu bir pozisyon almak için zaman vermek gerekir. Hemen aramamalısın stopUpdatingLocation. En fazla 10 saniye veya önbelleğe alınmamış yüksek doğruluklu bir konum elde edene kadar çalışmasına izin verdik.

  4. Önbelleğe alınmış konumları filtrelemeniz ve minimum gerekli doğruluğu karşıladığından emin olmak için aldığınız konumun doğruluğunu kontrol etmeniz gerekir ( buraya bakın ). Aldığınız ilk güncelleme 10 dakika veya 10 günlük olabilir. İlk aldığınız doğruluk 3000m olabilir.

  5. Bunun yerine önemli konum değişikliği API'larını kullanmayı düşünün. Önemli değişiklik bildirimini aldığınızda, CLLocationManageryüksek doğrulukta bir konum elde etmek için birkaç saniye başlayabilirsiniz . Emin değilim, önemli konum değiştirme hizmetlerini hiç kullanmadım.


Apple CoreLocationreferansı, beginBackgroundTaskWithExpirationHandlerkonum verilerini arka planda işlerken kullanılmasını öneriyor gibi görünüyor : "Bir iOS uygulamasının konum verilerini işlemek için daha fazla zamana ihtiyacı varsa, beginBackgroundTaskWithName: expirationHandler: UIApplication sınıfının yöntemini kullanarak daha fazla arka planda yürütme süresi isteyebilir." - developer.apple.com/library/ios/documentation/UserExperience/…
eliocs

4
_locationManager.allowsBackgroundLocationUpdates = YES eklemeyi unutmayın; iOS9 + için, aksi takdirde uygulama 180 saniye sonra uyku moduna geçer
kolyancz

@kolyancz iPhone 6+ için iOS 10.1.1'de denedim. Uykuya dalması ve tetiklenmesi yaklaşık 17 dakika sürdü locationManagerDidPauseLocationUpdates. Bu davranışı 10 kez doğruladım!
Honey

Neden tartışmalı olduğunu söylediğinizi gerçekten anlamıyorum ve sonra bir arka plana sarmanız gerektiğini söylüyorsunuz
Tatlım

10

Konum hizmetini başlatma ve arka plan görevini durdurma zamanı geldiğinde, arka plan görevi bir gecikmeyle durdurulmalıdır (1 saniye yeterli olmalıdır). Aksi takdirde konum hizmeti başlamaz. Ayrıca Konum Hizmeti birkaç saniye (ör. 3 saniye) AÇIK bırakılmalıdır.

Bir cocoapod APScheduledLocationManager , her n saniyede bir istenen konum doğruluğu ile arka planda konum güncellemelerini almaya izin verir .

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

Depo ayrıca Swift 3 ile yazılmış bir örnek uygulama içerir.


1

startMonitoringSignificantLocationChanges:API ile denemeye ne dersiniz ? Kesinlikle daha az frekansla ateşleniyor ve doğruluğu oldukça iyi. Ek olarak, diğer locationManagerAPI'leri kullanmaktan çok daha fazla avantajı vardır .

Bu API ile ilgili çok daha fazlası bu bağlantıda zaten tartışıldı


1
Bu yaklaşımı denedim. Bu doğruluk şartı ihlal - dan docs : This interface delivers new events only when it detects changes to the device’s associated cell towers
pcoving

1

İnfo.plist'e aşağıdaki anahtarı ekleyerek uygulamanıza konum güncelleme modunu eklemeniz gerekir.

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

didUpdateToLocationyöntem çağrılacaktır (uygulamanız arka planda olsa bile). Bu yöntem çağrısı temelinde her şeyi gerçekleştirebilirsiniz.


Konum güncelleme modu zaten info.plist'te. Bahsettiğim gibi, 180 saniyelik arka plan zaman aşımına kadar güncellemeler alıyorum.
pcoving

0

İOS 8'den sonra, Apple tarafından yapılan CoreLocation çerçevesiyle ilgili arka plan getirme ve güncellemelerinde birkaç değişiklik var.

1) Apple, uygulamadaki konum güncellemesini almak için AlwaysAuthorization isteğini sunar.

2) Apple, iOS'ta arka plandan konum getirmek için backgroundLocationupdates'i tanıttı.

Arka planda konum almak için Xcode'un Yeteneklerinde Konum Güncellemesini etkinleştirmeniz gerekir.

//
//  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

Uygulama arka plandayken standart konum hizmetlerini kullanmak için önce Hedef ayarlarının Yetenekler sekmesindeki Arka Plan Modlarını açmanız ve Konum güncellemeleri seçeneğini belirlemeniz gerekir.

Veya doğrudan Info.plist'e ekleyin .

<key>NSLocationAlwaysUsageDescription</key>
 <string>I want to get your location Information in background</string>
<key>UIBackgroundModes</key>
 <array><string>location</string> </array>

O zaman CLLocationManager'ı kurmanız gerekir

Hedef 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,*) {
    self.locationManager.requestAlwaysAuthorization()
}
if #available (iOS 9.0,*) {
    self.locationManager.allowsBackgroundLocationUpdates = true
}
self.locationManager.startUpdatingLocation()

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


-2
locationManager.allowsBackgroundLocationUpdates = true

4
Cevabınızı düzenleyebilir ve bunun sorunu neden / nasıl çözdüğüne dair bazı açıklamalar ekleyebilir misiniz ?
barbsan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.