I am trying to implement directions with clLocationManager in a project. Everything is working ok, but the didEnterrRegion function is very slow to fire. When testing, I enter the region but only 2-3 minutes after exiting the region I get the callback. Does anyone have any suggestion on how to improve this? This is the locationManager:
private lazy var locationManager: CLLocationManager = {
let locationManager = CLLocationManager()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.distanceFilter = kCLDistanceFilterNone
handleAuthorizationStatus(locationManager: locationManager)
} else {
//TODO: Handle error
}
return locationManager
}()
This is which regions I am tracking, here I am also drawing each region to easier see when I enter specific region:
private func getRouteSteps(_ mapView: MKMapView, route: MKRoute) {
for monitoredRegion in locationManager.monitoredRegions {
locationManager.stopMonitoring(for: monitoredRegion)
}
let steps = route.steps
self.steps = steps
for i in 0..<steps.count {
let step = steps[i]
let region = CLCircularRegion(center: step.polyline.coordinate, radius: 30, identifier: "\(i)")
let circle = MKCircle(center: region.center, radius: region.radius)
mapView.addOverlay(circle)
locationManager.startMonitoring(for: region)
}
stepCounter += 1
let initialMessage = "Om \(Int(steps[stepCounter].distance)) meter \(steps[stepCounter].instructions.lowercased())"
directionMessage = initialMessage
}
This is the locationManager-function:
extension MapViewModel: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// manager.stopUpdatingLocation()
if directionsViewState != .isShowingRoute {
if let location = locations.last {
self.didUpdateRegion = "Updated region with accuracy: \(location.horizontalAccuracy)"
let center = location.coordinate
setNewRegionForMapView(center: center)
isCenteringUserLocation = true
}
}
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
handleAuthorizationStatus(locationManager: locationManager)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
self.didEnterregion = "Entered region: \(region.identifier)"
stepCounter += 1
if stepCounter < steps.count {
let message = "Om \(Int(steps[stepCounter].distance)) meter \(steps[stepCounter].instructions.lowercased())"
directionMessage = message
let speechUtterance = AVSpeechUtterance(string: message)
speechSynthesizer.speak(speechUtterance)
} else {
directionMessage = "You have arrived at your destination!"
stepCounter = 0
let speechUtterance = AVSpeechUtterance(string: directionMessage)
speechSynthesizer.speak(speechUtterance)
for monitoredRegion in locationManager.monitoredRegions {
locationManager.stopMonitoring(for: monitoredRegion)
}
}
}
}
I am also calling locationManager.startUpdatingLocations in the init-method.
Suppose that you are using
locationManager.requestWhenInUseAuthorization().So, I have some suggestions for you:
[METHOD 1] Apply background location updating: Enable background mode to your target
Then add these lines of code:
The line
allowsBackgroundLocationUpdates = truewill allow your app to run in the background to receive new location event (ex: lock screen, use another app,...).And,
pausesLocationUpdatesAutomatically = falsewill tell the system to not pause location updating, system can pause background location updating to save battery.Call your
locationManager.startUpdatingLocation()to start listening for new location change.Next [METHOD 2], if above method doesn't work, you can switch to use
locationManager.requestAlwaysAuthorization(). Its description isRequests the user’s permission to use location services regardless of whether the app is in use.System can wake your app to run in background to handle new location events. Remember to add the permission description forrequestAlwaysAuthorizationinInfo.plistfile.Next [METHOD 3], try to increase your
CLCircularRegion's radiusto higher value, ex: 50 meters. Or you can try to increase thedistanceFilterto 2 meters,distanceFilter = noneisn't a best option.Finally [METHOD 4], Make your customized region monitoring logic by calculating distance from user's location to region's center whenever we get a new location event, use this one
func distance(from location: CLLocation) -> CLLocationDistance. If distance is <= your region's radius, that means user already crossed the boundary.Hope that you can solve your problem.