Saya sedang menulis aplikasi yang membutuhkan pembaruan lokasi latar belakang dengan akurasi tinggi dan frekuensi rendah . Solusinya tampaknya menjadi tugas NSTimer latar belakang yang memulai pembaruan pengelola lokasi, yang kemudian segera dimatikan. Pertanyaan ini telah ditanyakan sebelumnya:
Bagaimana cara mendapatkan pembaruan lokasi latar belakang setiap n menit di aplikasi iOS saya?
Mendapatkan lokasi pengguna setiap n menit setelah aplikasi beralih ke latar belakang
iOS Bukan masalah pengatur waktu pelacakan lokasi latar belakang biasa
Timer latar belakang iOS yang berjalan lama dengan mode latar belakang "lokasi"
Layanan latar belakang penuh waktu iOS berdasarkan pelacakan lokasi
tetapi saya belum mendapatkan contoh minimum yang berfungsi. Setelah mencoba setiap permutasi dari jawaban yang diterima di atas, saya mengumpulkan titik awal. Memasuki latar belakang:
- (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];
}
dan metode delegasi:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(@"%@", newLocation);
NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[self.locationManager stopUpdatingLocation];
}
Perilaku saat ini adalah bahwa backgroundTimeRemaining
penurunan dari 180 detik ke nol (saat pencatatan lokasi), dan kemudian pengendali kedaluwarsa dijalankan dan tidak ada pembaruan lokasi lebih lanjut yang dibuat. Bagaimana cara mengubah kode di atas untuk menerima pembaruan lokasi berkala di latar belakang tanpa batas waktu ?
Pembaruan : Saya menargetkan iOS 7 dan tampaknya ada beberapa bukti bahwa tugas latar belakang berperilaku berbeda:
Jawaban:
Tampaknya itulah
stopUpdatingLocation
yang memicu pengatur waktu pengawas latar belakang, jadi saya menggantinyadidUpdateLocation
dengan:[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]; [self.locationManager setDistanceFilter:99999];
yang tampaknya mematikan GPS secara efektif. Pemilih untuk latar belakang
NSTimer
kemudian menjadi:- (void) changeAccuracy { [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; }
Yang saya lakukan adalah mengubah akurasi secara berkala untuk mendapatkan koordinat akurasi tinggi setiap beberapa menit dan karena
locationManager
belum dihentikan,backgroundTimeRemaining
tetap pada nilai maksimumnya. Ini mengurangi konsumsi baterai dari ~ 10% per jam (dengankCLLocationAccuracyBest
latar belakang konstan ) menjadi ~ 2% per jam di perangkat saya.sumber
Saya memang menulis aplikasi menggunakan layanan Lokasi, aplikasi harus mengirim lokasi setiap 10 detik. Dan itu bekerja dengan sangat baik.
Cukup gunakan metode " allowDeferredLocationUpdatesUntilTraveled: timeout ", mengikuti dokumen Apple.
Langkah-langkahnya adalah sebagai berikut:
Diperlukan: Daftarkan mode latar belakang untuk memperbarui Lokasi.
1. Buat LocationManger dan startUpdatingLocation, dengan akurasi dan filteredDistance sesuai keinginan Anda:
-(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. Agar aplikasi tetap berjalan selamanya menggunakan metode "allowDeferredLocationUpdatesUntilTraveled: timeout" di latar belakang, Anda harus memulai ulang updateLocation dengan parameter baru saat aplikasi berpindah ke latar belakang, seperti ini:
- (void)applicationWillResignActive:(UIApplication *)application { _isBackgroundMode = YES; [_locationManager stopUpdatingLocation]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [_locationManager setDistanceFilter:kCLDistanceFilterNone]; _locationManager.pausesLocationUpdatesAutomatically = NO; _locationManager.activityType = CLActivityTypeAutomotiveNavigation; [_locationManager startUpdatingLocation]; }
3. Aplikasi mendapatkan updateLocations seperti biasa dengan callback "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. Namun Anda harus menangani data di kemudian "locationManager: didFinishDeferredUpdatesWithError:" callback untuk tujuan Anda
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { _deferringUpdates = NO; //do something }
5. CATATAN: Saya pikir kita harus mengatur ulang parameter LocationManager setiap kali aplikasi beralih antara mode latar belakang / latar belakang.
sumber
allowsBackgroundLocationUpdates = YES
danrequestAlwaysAuthorization
ataurequestWhenInUseAuthorization
. Misalnya: `CLLocationManager * locationManager = [[CLLocationManager alokasi] init]; locationManager.delegate = self; locationManager.allowsBackgroundLocationUpdates = YA; [locationManager requestAlwaysAuthorization]; [locationManager startUpdatingLocation]; `Jika Anda memiliki
UIBackgroundModes
di plist Anda denganlocation
kunci maka Anda tidak perlu menggunakanbeginBackgroundTaskWithExpirationHandler
metode. Itu berlebihan. Juga Anda menggunakannya secara tidak benar (lihat di sini ) tetapi itu diperdebatkan karena plist Anda diatur.Dengan
UIBackgroundModes location
di plist aplikasi akan terus berjalan di latar belakang tanpa batas waktu hanya selamaCLLocationManger
berjalan. Jika Anda meneleponstopUpdatingLocation
saat berada di latar belakang maka aplikasi akan berhenti dan tidak akan mulai lagi.Mungkin Anda dapat menelepon
beginBackgroundTaskWithExpirationHandler
sebelum meneleponstopUpdatingLocation
dan setelah meneleponstartUpdatingLocation
Anda dapat memanggilnyaendBackgroundTask
agar tetap di latar belakang saat GPS dihentikan, tetapi saya tidak pernah mencobanya - ini hanya sebuah ide.Opsi lain (yang belum saya coba) adalah menjaga pengelola lokasi tetap berjalan saat berada di latar belakang tetapi setelah Anda mendapatkan lokasi yang akurat, ubah
desiredAccuracy
properti menjadi 1000m atau lebih tinggi untuk memungkinkan chip GPS dimatikan (untuk menghemat baterai). Kemudian 10 menit kemudian ketika Anda membutuhkan pembaruan lokasi lainnya, ubahdesiredAccuracy
kembali ke 100m untuk mengaktifkan GPS sampai Anda mendapatkan lokasi yang akurat, ulangi.Saat Anda memanggil
startUpdatingLocation
manajer lokasi, Anda harus memberinya waktu untuk mendapatkan posisi. Anda tidak harus segera meneleponstopUpdatingLocation
. Kami membiarkannya berjalan maksimal 10 detik atau sampai kami mendapatkan lokasi akurasi tinggi yang tidak di-cache.Anda perlu memfilter lokasi cache dan memeriksa keakuratan lokasi yang Anda dapatkan untuk memastikannya memenuhi keakuratan minimum yang diperlukan (lihat di sini ). Pembaruan pertama yang Anda dapatkan mungkin berumur 10 menit atau 10 hari. Akurasi pertama yang Anda dapatkan mungkin 3000m.
Pertimbangkan untuk menggunakan API perubahan lokasi yang signifikan sebagai gantinya. Setelah Anda mendapatkan pemberitahuan perubahan signifikan, Anda dapat memulai
CLLocationManager
selama beberapa detik untuk mendapatkan posisi akurasi tinggi. Saya tidak yakin, saya tidak pernah menggunakan layanan perubahan lokasi yang signifikan.sumber
CoreLocation
Referensi Apple tampaknya merekomendasikan penggunaanbeginBackgroundTaskWithExpirationHandler
saat memproses data lokasi di latar belakang: "Jika aplikasi iOS membutuhkan lebih banyak waktu untuk memproses data lokasi, ia dapat meminta lebih banyak waktu eksekusi latar belakang menggunakan metode beginBackgroundTaskWithName: expirationHandler: kelas UIApplication." - developer.apple.com/library/ios/documentation/UserExperience/…locationManagerDidPauseLocationUpdates
. Saya memverifikasi perilaku itu 10 kali!Jika sudah waktunya untuk memulai layanan lokasi dan menghentikan tugas latar belakang, tugas latar belakang harus dihentikan dengan penundaan (1 detik sudah cukup). Jika tidak, layanan lokasi tidak akan dimulai. Juga Layanan Lokasi harus dibiarkan ON selama beberapa detik (misalnya 3 detik).
Ada cocoapod APScheduledLocationManager yang memungkinkan untuk mendapatkan pembaruan lokasi latar belakang setiap n detik dengan akurasi lokasi yang diinginkan.
let manager = APScheduledLocationManager(delegate: self) manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
Repositori juga berisi aplikasi contoh yang ditulis di Swift 3.
sumber
Bagaimana kalau mencobanya dengan
startMonitoringSignificantLocationChanges:
API? Ini pasti menembak dengan frekuensi yang lebih sedikit dan akurasinya cukup baik. Selain itu, ia memiliki lebih banyak keuntungan daripada menggunakanlocationManager
API lain .Lebih banyak tentang API ini telah dibahas di tautan ini
sumber
This interface delivers new events only when it detects changes to the device’s associated cell towers
Anda perlu menambahkan mode pembaruan lokasi di aplikasi Anda dengan menambahkan kunci berikut di info.plist Anda.
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
didUpdateToLocation
metode akan dipanggil (bahkan saat aplikasi Anda berada di latar belakang). Anda dapat melakukan apa saja atas dasar pemanggilan metode inisumber
Setelah iOS 8, ada beberapa perubahan dalam kerangka kerja CoreLocation terkait pengambilan latar belakang dan pembaruan yang dibuat oleh apple.
1) Apple memperkenalkan permintaan AlwaysAuthorization untuk mengambil pembaruan lokasi di aplikasi.
2) Apple memperkenalkan backgroundLocationupdates untuk mengambil lokasi dari latar belakang di iOS.
Untuk mengambil lokasi di latar belakang, Anda perlu mengaktifkan Pembaruan Lokasi dalam Kemampuan 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 } }
sumber
Untuk menggunakan layanan lokasi standar saat aplikasi berada di latar belakang, pertama-tama Anda perlu mengaktifkan Mode Latar Belakang di tab Kapabilitas pada pengaturan Target, dan pilih Pembaruan lokasi.
Atau, tambahkan langsung ke Info.plist .
<key>NSLocationAlwaysUsageDescription</key> <string>I want to get your location Information in background</string> <key>UIBackgroundModes</key> <array><string>location</string> </array>
Kemudian Anda perlu menyiapkan CLLocationManager
Tujuan 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];
Cepat
self.locationManager.delegate = self if #available (iOS 8.0,*) { self.locationManager.requestAlwaysAuthorization() } if #available (iOS 9.0,*) { self.locationManager.allowsBackgroundLocationUpdates = true } self.locationManager.startUpdatingLocation()
Ref: https://medium.com/@javedmultani16/location-service-in-the-background-ios-942c89cd99ba
sumber
locationManager.allowsBackgroundLocationUpdates = true
sumber