Szukam sposobu, aby uzyskać aktualizację lokalizacji w tle co n minut w mojej aplikacji na iOS. Korzystam z iOS 4.3 i rozwiązanie powinno działać na iPhone'ach bez jailbreaku.
Próbowałem / rozważałem następujące opcje:
CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges
: Działa to w tle zgodnie z oczekiwaniami, w oparciu o skonfigurowane właściwości, ale wydaje się, że nie można zmusić go do aktualizacji lokalizacji co n minutNSTimer
: Działa, gdy aplikacja działa na pierwszym planie, ale wydaje się, że nie jest przeznaczona do zadań w tle- Powiadomienia lokalne: powiadomienia lokalne można planować co n minut, ale nie można wykonać kodu, aby uzyskać bieżącą lokalizację (bez konieczności uruchamiania aplikacji za pośrednictwem powiadomienia). Podejście to również nie wydaje się podejściem czystym, ponieważ nie do tego należy używać powiadomień.
UIApplication:beginBackgroundTaskWithExpirationHandler
: O ile rozumiem, należy tego użyć do zakończenia niektórych prac w tle (również ograniczonych czasowo), gdy aplikacja zostanie przeniesiona w tło, zamiast wdrażania „długotrwałych” procesów w tle.
Jak mogę wdrożyć te regularne aktualizacje lokalizacji w tle?
Odpowiedzi:
Znalazłem rozwiązanie do wdrożenia tego za pomocą forów Apple Developer:
location background mode
NSTimer
w tle za pomocąUIApplication:beginBackgroundTaskWithExpirationHandler:
n
jest mniejszy niżUIApplication:backgroundTimeRemaining
będzie działał dobrze. Gdyn
jest większy ,location manager
należy go ponownie włączyć (i wyłączyć), zanim nie pozostanie czas, aby uniknąć zabicia zadania w tle.Działa to, ponieważ lokalizacja jest jednym z trzech dozwolonych typów wykonywania w tle .
Uwaga: straciłem trochę czasu, testując to w symulatorze, gdzie to nie działa. Działa to jednak dobrze na moim telefonie.
źródło
W systemie iOS 8/9/10, aby aktualizować lokalizację w tle co 5 minut, wykonaj następujące czynności:
Przejdź do projektu -> Możliwości -> Tryby tła -> wybierz Aktualizacje lokalizacji
Przejdź do projektu -> Informacje -> dodaj klucz NSLocationAlwaysUsageDescription z pustą wartością (lub opcjonalnie dowolnym tekstem)
Aby lokalizacja działała, gdy aplikacja jest w tle, i wysyłaj współrzędne do serwisu internetowego lub rób z nimi cokolwiek co 5 minut, implementuj ją jak w poniższym kodzie.
Nie używam żadnych zadań ani timerów w tle. Testowałem ten kod na moim urządzeniu z iOS 8.1, które leżało na moim biurku przez kilka godzin, a moja aplikacja działała w tle. Urządzenie zostało zablokowane, a kod działał poprawnie cały czas.
źródło
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Zrobiłem to w opracowywanej przeze mnie aplikacji. Timery nie działają, gdy aplikacja jest w tle, ale aplikacja stale otrzymuje aktualizacje lokalizacji. Przeczytałem gdzieś w dokumentacji (wydaje się, że nie mogę jej teraz znaleźć, opublikuję aktualizację, gdy to zrobię), że metodę można wywołać tylko w aktywnej pętli uruchamiania, gdy aplikacja jest w tle. Delegat aplikacji ma aktywną pętlę uruchamiania, nawet w tle, więc nie musisz tworzyć własnej, aby to działało. [Nie jestem pewien, czy to prawidłowe wyjaśnienie, ale tak zrozumiałem z tego, co przeczytałem]
Przede wszystkim dodaj
location
obiekt kluczaUIBackgroundModes
do info.plist swojej aplikacji. Teraz musisz rozpocząć aktualizację lokalizacji w dowolnym miejscu aplikacji:Następnie napisz metodę obsługi aktualizacji lokalizacji, powiedzmy
-(void)didUpdateToLocation:(CLLocation*)location
, w delegacie aplikacji. Następnie wdrożyć metodęlocationManager:didUpdateLocation:fromLocation
zCLLocationManagerDelegate
w klasie, w której rozpoczął kierownik lokalizacji (od ustawiamy Location Manager delegatem „ja”). Wewnątrz tej metody musisz sprawdzić, czy upłynął przedział czasu, po którym musisz obsłużyć aktualizacje lokalizacji. Możesz to zrobić, zapisując za każdym razem aktualny czas. Jeśli ten czas minął, wywołaj metodę UpdateLocation od delegata aplikacji:Spowoduje to wywołanie metody co 5 minut, nawet gdy aplikacja jest w tle. Imp: Ta implementacja wyczerpuje baterię, jeśli dokładność danych lokalizacji nie jest krytyczna, powinieneś użyć
[locationManager startMonitoringSignificantLocationChanges]
Przed dodaniem tego do aplikacji przeczytaj Przewodnik po programowaniu rozpoznawania lokalizacji
źródło
Teraz, gdy iOS6 jest obecnie najlepszym sposobem, aby mieć zawsze działające usługi lokalizacyjne, ...
Właśnie przetestowałem to w ten sposób:
Uruchomiłem aplikację, idę w tle i poruszam się w samochodzie o kilka minut. Potem wracam do domu na 1 godzinę i znów zaczynam się przeprowadzać (bez ponownego otwierania aplikacji). Lokalizacje zaczęły się od nowa. Następnie zatrzymał się na dwie godziny i zaczął od nowa. Wszystko znowu w porządku ...
NIE ZAPOMNIJ UŻYWAĆ nowych usług lokalizacyjnych w iOS6
źródło
Dla kogoś innego, kto ma koszmar, wymyśl to. Mam proste rozwiązanie.
Dodaj licznik czasu, używając:
Po prostu nie zapomnij dodać „Rejestrów aplikacji do aktualizacji lokalizacji” w info.plist.
źródło
Oto czego używam:
Zaczynam śledzenie w AppDelegate w ten sposób:
źródło
Niestety wszystkie twoje założenia wydają się słuszne i nie sądzę, aby można to zrobić. Aby oszczędzać baterię, usługi lokalizacyjne iPhone'a są oparte na ruchu. Jeśli telefon znajduje się w jednym miejscu, jest niewidoczny dla usług lokalizacyjnych.
CLLocationManager
Zadzwoni tylkolocationManager:didUpdateToLocation:fromLocation:
wtedy, gdy telefon odbiera aktualizacji lokalizacji, co się dzieje, jeśli tylko jeden z trzech usług lokalizacyjnych (wieża komórka, GPS, WiFi) postrzega zmianę.Kilka innych rzeczy, które mogą pomóc w uzyskaniu informacji o dalszych rozwiązaniach:
Uruchomienie i zatrzymanie usług powoduje
didUpdateToLocation
wywołanie metody delegowanej, alenewLocation
może mieć stary znacznik czasu.Monitorowanie regionu może pomóc
Podczas pracy w tle należy pamiętać, że uzyskanie pełnej „obsługi” usług lokalizacyjnych zatwierdzonych przez Apple może być trudne. Z tego, co widziałem, zostały one zaprojektowane specjalnie
startMonitoringSignificantLocationChanges
jako energooszczędna alternatywa dla aplikacji, które wymagają obsługi lokalizacji w tle, i zdecydowanie zachęcają programistów do korzystania z niej, chyba że aplikacja absolutnie tego potrzebuje.Powodzenia!
AKTUALIZACJA: Te myśli mogą być już nieaktualne. Wygląda na to, że ludzie odnoszą sukcesy z odpowiedzią @wjans powyżej.
źródło
startMonitoringSignificantLocationChanges
nie dałbym żadnej aktualizacji w tym przypadku.Napisałem aplikację za pomocą usług lokalizacyjnych, aplikacja musi wysyłać lokalizację co 10s. I działało bardzo dobrze.
Wystarczy użyć metody „ allowDeferredLocationUpdatesUntilTraveled: timeout ”, postępując zgodnie z dokumentem Apple.
To co zrobiłem to:
Wymagane: Zarejestruj tryb tła dla aktualizacji Lokalizacja.
1. Twórz
LocationManger
i zastartUpdatingLocation
pomocąaccuracy
ifilteredDistance
jak chcesz:2. Aby aplikacja działała nieprzerwanie przy użyciu
allowDeferredLocationUpdatesUntilTraveled:timeout
metody w tle, musisz ponownie uruchomićupdatingLocation
nowy parametr, gdy aplikacja przejdzie do tła, w następujący sposób:3. Aplikacja jest aktualizowana jak zwykle z
locationManager:didUpdateLocations:
oddzwanianiem:4. Ale powinieneś obsłużyć dane, a następnie
locationManager:didFinishDeferredUpdatesWithError:
oddzwonić w swoim celu5. UWAGA: Myślę, że powinniśmy zresetować parametry
LocationManager
każdym razem, gdy aplikacja przełącza się między trybem tła / forgroundu.źródło
pausesLocationUpdatesAutomatically = true
informuje menedżera lokalizacji, aby wstrzymywał aktualizacje, jeśli pozornie nie ma zmiany lokalizacji ( dokument Apple ). W każdym razie nie testowałemlocation manager pauses updates
jeszcze wyraźnie przypadku : D.pausesLocationUpdatesAutomatically = true
powoduje, że moja aplikacja przestaje aktualizować lokalizację.Jest to potrzebne do śledzenia lokalizacji w tle od iOS 9.
źródło
Użyłem metody xs2bush, aby uzyskać interwał (użycie
timeIntervalSinceDate
) i trochę go rozwinąłem. Chciałem się upewnić, że uzyskuję wymaganą dokładność, której potrzebowałem, a także że nie wyczerpuję baterii, utrzymując radio GPS więcej niż to konieczne.Utrzymuję lokalizację działającą nieprzerwanie z następującymi ustawieniami:
jest to stosunkowo niski poziom zużycia baterii. Kiedy będę gotowy do następnego okresowego odczytu lokalizacji, najpierw sprawdzam, czy lokalizacja mieści się w mojej pożądanej dokładności, a jeśli tak, to używam lokalizacji. Jeśli nie, zwiększam dokładność o:
uzyskaj moją lokalizację, a następnie, gdy już ją znajdę, ponownie zmniejszam dokładność, aby zminimalizować zużycie baterii. Napisałem pełną działającą próbkę tego, a także napisałem źródło kodu po stronie serwera w celu zebrania danych o lokalizacji, przechowywania ich w bazie danych i umożliwienia użytkownikom przeglądania danych GPS w czasie rzeczywistym lub pobierania i przeglądania wcześniej zapisanych tras. Mam klientów na iOS, Androida, Windows Phone i java ja. Wszyscy klienci są napisani w sposób natywny i wszyscy działają poprawnie w tle. Projekt jest na licencji MIT.
Projekt systemu iOS jest przeznaczony dla systemu iOS 6 przy użyciu podstawowego zestawu SDK systemu iOS 7. Kod można pobrać tutaj .
Jeśli zauważysz jakiekolwiek problemy, zgłoś problem na github. Dzięki.
źródło
Wygląda na to, że stopUpdatingLocation wyzwala licznik czasu nadzorowania w tle, więc zastąpiłem go w didUpdateLocation:
który wydaje się skutecznie wyłączać GPS. Selektor tła NSTimer staje się wtedy:
Wszystko, co robię, to okresowe przełączanie dokładności w celu uzyskania współrzędnych o wysokiej dokładności co kilka minut, a ponieważ nie udało się zatrzymać locationManager, backgroundTimeRemaining pozostaje na maksymalnej wartości. To zmniejszone zużycie baterii z ~ 10% na godzinę (ze stałym kCLLocationAccuracyBest w tle) do ~ 2% na godzinę na moim urządzeniu
źródło
Istnieje cocoapod APScheduledLocationManager, który pozwala otrzymywać aktualizacje lokalizacji w tle co n sekund z pożądaną dokładnością lokalizacji.
Repozytorium zawiera także przykładową aplikację napisaną w Swift 3.
źródło
W iOS 9 i watchOS 2.0 w CLLocationManager dostępna jest nowa metoda, która pozwala zażądać bieżącej lokalizacji: CLLocationManager: requestLocation (). To kończy się natychmiast, a następnie zwraca lokalizację do delegata CLLocationManager.
Możesz użyć NSTimer do żądania lokalizacji co minutę za pomocą tej metody i nie musisz pracować z metodami startUpdatingLocation i stopUpdatingLocation.
Jeśli jednak chcesz przechwytywać lokalizacje na podstawie zmiany X metrów od ostatniej lokalizacji, po prostu ustaw właściwość distanceFilter CLLocationManger i wywołaj funkcję X startUpdatingLocation ().
źródło
W załączeniu znajduje się szybkie rozwiązanie oparte na:
Definiować
App registers for location updates
w info.plistUtrzymuj działanie menedżera położenia przez cały czas
Przełączaj
kCLLocationAccuracy
pomiędzyBestForNavigation
(przez 5 sekund, aby uzyskać lokalizację) aThreeKilometers
przez resztę okresu oczekiwania, aby uniknąć rozładowania bateriiTen przykład aktualizuje lokalizację co 1 minutę na pierwszym planie i co 15 minut w tle.
Przykład działa dobrze z Xcode 6 Beta 6, działającym na urządzeniu z systemem iOS 7.
W delegacie aplikacji (mapView jest opcjonalnym wskazaniem kontrolera mapView)
W mapView (locationManager wskazuje obiekt w AppDelegate)
źródło