#ios #swift #cllocationmanager #appdelegate
#iOS #swift #cllocationmanager #appdelegate
Вопрос:
Я создал приложение, в котором вы можете нажать кнопку «Пуск». После нажатия кнопки приложение будет получать местоположение пользователя каждые 10 секунд вплоть до нажатия кнопки остановки. Когда я выхожу из приложения или если экран становится черным, оно больше не получит никаких местоположений, пока я не войду в приложение повторно.
Итак, в настоящее время я пытаюсь обновить местоположения, когда приложение свернуто. (Я предполагаю, что это вызывается в фоновом режиме?), а также когда экран становится черным. Но мои вопросы:
- Должен ли я написать этот код в AppDelegate?, если да. Как я могу узнать, была нажата кнопка или нет?
- Куда именно в AppDelegate я должен добавить код? И как я могу передать местоположения обратно правильному ViewController? (Поскольку я не могу выполнить какую-либо подготовку к переходу из AppDelegate)
Если вы знаете ответы на эти вопросы, пожалуйста, не стесняйтесь отвечать на них. 🙂 Я был бы действительно признателен за это!
Комментарии:
1. Получили ли вы разрешение от пользователя на использование служб определения местоположения, пока пользователь использует другие приложения?
2. @RamyMohamed Я не уверен насчет этого разрешения. Но я активировал «Обновления местоположения» в «Фоновых режимах», я также установил 2 разрешения в info-plist: * Местоположение всегда и * Местоположение при использовании
3. ознакомьтесь с этим блогом: medium.com/curbside /…
4. Итак, вы хотите обновлять местоположения через регулярные промежутки времени, скажем, каждые 10 секунд, когда приложение работает в фоновом режиме. Для достижения этого вам необходимо запустить таймер для извлечения местоположения через регулярные промежутки времени. Но невозможно запустить таймер, когда приложение работает в фоновом режиме. Как только приложения войдут в BG, оно будет приостановлено раньше. Для обновления местоположения, когда приложение находится в BG, можно использовать либо службу определения местоположения, либо службу гео-ограждения. Эти обе службы будут работать, даже если приложение завершено.
5. SLC и Geo Fencing имеют свои собственные оговорки, такие как точность не будет правильной, невозможно настроить интервалы и так далее. Как только вы ознакомитесь с этим документом, вы поймете больше: developer.apple.com/documentation/corelocation /… , developer.apple.com/documentation/corelocation /…
Ответ №1:
Лучший способ получить местоположение пользователя в фоновом режиме — использовать службу определения местоположения с существенными изменениями в соответствии с документацией Apple поместите эту функцию в свой класс:
func startReceivingSignificantLocationChanges() {
let authorizationStatus = CLLocationManager.authorizationStatus()
if authorizationStatus != .authorizedAlways {
// User has not authorized access to location information.
return
}
if !CLLocationManager.significantLocationChangeMonitoringAvailable() {
// The service is not available.
return
}
locationManager.delegate = self
locationManager.startMonitoringSignificantLocationChanges()
}
а также эта функция:
func locationManager(_ manager: CLLocationManager, didUpdateLocations
locations: [CLLocation]) {
let lastLocation = locations.last!
// Do something with the location.
}
итак, вам просто нужно вызвать startReceivingSignificantLocationChanges () внутри вашей кнопки, и это вызовет LocationManager (_ manager: CLLocationManager,didUpdateLocations locations: [CLLocation]), так что делайте с местоположением там, что хотите.
Не забудьте запросить разрешение на использование местоположения и прекратить отслеживание с помощью locationManager.stopMonitoringSignificantLocationChanges()
Комментарии:
1. Очень интересно! Итак. Мне не нужно ничего вызывать в делегате приложения? И в соответствии с вашим первым фрагментом. Я не должен ничего делать внутри скобок по адресу: // Пользователь не авторизовал доступ к информации о местоположении и // Служба недоступна.?
2. Хорошо, код добавлен в мое приложение. Только один вопрос: как я могу автоматически обновить его примерно через 10 секунд? или через несколько метров? Я имею в виду, мне нужно, чтобы оно обновлялось очень часто. Я надеюсь, вы меня поняли, спасибо!
3. ‘Мне не нужно ничего вызывать в делегате приложения?’ Нет, в любом случае не для этого ‘Я не должен ничего делать внутри скобок’ вы должны справиться с этим, может быть, вы могли бы показать всплывающее предупреждение пользователю или что-то в этом роде
4. Что вы имеете в виду?
5. В любом случае, я добавил этот код в свое приложение. Но как часто оно обновляется? Каждые 500 метров или около того? Мне нужно обновлять очень часто, например, каждые 20 метров или каждые 10 секунд. Возможно ли это? Спасибо.
Ответ №2:
- Получить разрешение на местоположение для Always Allow
-
Установите для диспетчера местоположений значение allowsBackgroundLocationUpdates true указанным выше способом вы можете получать местоположение при каждом изменении местоположения, сохранять эту информацию и отправлять ее на сервер. Ниже приведен пример кода
введите LocateMeCallback = (_ location: CLLocation?) -> Void
/* LocationTracker to track the user in while navigating from one place to other and store new locations in locations array. **/ class LocationTracker: NSObject { static let shared = LocationTracker() var lastLocation: CLLocation? var locations: [CLLocation] = [] var previousLocation: CLLocation? var isPreviousIsSameAsCurrent: Bool { if let previous = previousLocation, let last = lastLocation { return previous == last } return false } var isAggressiveModeOn = false var locationManager: CLLocationManager = { let locationManager = CLLocationManager() locationManager.allowsBackgroundLocationUpdates = true locationManager.pausesLocationUpdatesAutomatically = true locationManager.activityType = .automotiveNavigation return locationManager }() var locateMeCallback: LocateMeCallback? var isCurrentLocationAvailable: Bool { if lastLocation != nil { return true } return false } func enableLocationServices() { locationManager.delegate = self switch CLLocationManager.authorizationStatus() { case .notDetermined: // Request when-in-use authorization initially locationManager.requestWhenInUseAuthorization() case .restricted, .denied: // Disable location features print("Fail permission to get current location of user") case .authorizedWhenInUse: // Enable basic location features enableMyWhenInUseFeatures() case .authorizedAlways: // Enable any of your app's location features enableMyAlwaysFeatures() } } func enableMyWhenInUseFeatures() { locationManager.startUpdatingLocation() locationManager.delegate = self escalateLocationServiceAuthorization() } func escalateLocationServiceAuthorization() { // Escalate only when the authorization is set to when-in-use if CLLocationManager.authorizationStatus() == .authorizedWhenInUse { locationManager.requestAlwaysAuthorization() } } func enableMyAlwaysFeatures() { enableCoarseLocationFetch() locationManager.startUpdatingLocation() locationManager.delegate = self } // Enable Rough Location Fetch func enableCoarseLocationFetch() { isAggressiveModeOn = false locationManager.desiredAccuracy = kCLLocationAccuracyKilometer locationManager.distanceFilter = 100 } // Enable Aggressive Location Fetch func enableAggressiveLocationFetch() { isAggressiveModeOn = true locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation locationManager.distanceFilter = 10 } func locateMe(callback: @escaping LocateMeCallback) { self.locateMeCallback = callback if lastLocation == nil { enableLocationServices() } else { callback(lastLocation) } } func startTracking() { enableLocationServices() } func stopTracking() { locationManager.stopUpdatingLocation() } func resetPreviousLocation() { previousLocation = nil } private override init() {}
}
extension LocationTracker: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { print(locations) guard let location = locations.first else { return } guard -location.timestamp.timeIntervalSinceNow < 120, // Validate only location fetched recently location.horizontalAccuracy > 0, // Validate Horizontal Accuracy - Ve means Invalid location.horizontalAccuracy < 200 // Validate Horizontal Accuracy > 100 M else { print("invalid location received OR ignore old (cached) updates") return } self.locations.append(location) lastLocation = location if let activeRide = RideManager.shared.activeRide, let _ = AccessTokenHelper.shared.accessToken, let activeRideId = activeRide.ride_id, let type = activeRide.rideStatusTypeOptional, type == .started { //Store Location For A particular Ride after Start LocationUpdater.shared.saveInDataBase(rideId: activeRideId, locations: [location]) } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print(error.localizedDescription) } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { enableLocationServices() } } /* This class having responsibility of Updating the location on server after n second and update path after n second. **/ class LocationTimer { static let time: Double = 30 } /* class to update locations to server after nth second **/ class LocationUpdater: NSObject { static let shared = LocationUpdater(n: Double(LocationTimer.time), tracker: LocationTracker.shared) let n: Double private let tracker: LocationTracker var timer: Timer! = nil init(n: Double, tracker: LocationTracker) { self.n = n self.tracker = tracker super.init() } func startUpdater() { self.timer?.invalidate() self.timer = nil self.timer = Timer.scheduledTimer(timeInterval: n, target: self, selector: #selector(updateLocationsToServer), userInfo: nil, repeats: true) self.timer.fire() } func stopUpdater() { self.timer?.invalidate() self.timer = nil } @objc func updateLocationsToServer() { // update to server } } // usage LocationTracker.shared.startTracking() LocationUpdater.shared.startUpdater()