It may or may not be a good solution but if I were you I would have used both startMonitoringSignificantLocationChanges
and regionMonitoring
.
Here is the sample I made which worked well with iOS 13.
Lets take regionMonitoring
first. We have certainly no problems when the app is in foreground state and we can use the CLLocationManager's didUpdate
delegate to get the location and send it to the server.
Keep latest current location in AppDelegate's property, lets say:
var lastLocation:CLLocation?
//And a location manager
var locationManager = CLLocationManager()
We have two UIApplicationDelegates
func applicationDidEnterBackground(_ application: UIApplication) {
//Create a region
}
func applicationWillTerminate(_ application: UIApplication) {
//Create a region
}
So whenever the user kills the app or makes the app go to background, we can certainly create a region around the latest current location fetched. Here is an example to create a region.
func createRegion(location:CLLocation?) {
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
let coordinate = CLLocationCoordinate2DMake((location?.coordinate.latitude)!, (location?.coordinate.longitude)!)
let regionRadius = 50.0
let region = CLCircularRegion(center: CLLocationCoordinate2D(
latitude: coordinate.latitude,
longitude: coordinate.longitude),
radius: regionRadius,
identifier: "aabb")
region.notifyOnExit = true
region.notifyOnEntry = true
//Send your fetched location to server
//Stop your location manager for updating location and start regionMonitoring
self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoring(for: region)
}
else {
print("System can't track regions")
}
}
Make use of RegionDelegates
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered Region")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Exited Region")
locationManager?.stopMonitoring(for: region)
//Start location manager and fetch current location
locationManager?.startUpdatingLocation()
}
Grab the location from didUpdate
method
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if UIApplication.shared.applicationState == .active {
} else {
//App is in BG/ Killed or suspended state
//send location to server
// create a New Region with current fetched location
let location = locations.last
lastLocation = location
//Make region and again the same cycle continues.
self.createRegion(location: lastLocation)
}
}
Here I have made a 50m region radius circle. I have tested this and it is called generally after crossing 100m from your center point.
Now the second approach can me using significantLocationChanges
On making the app go background or terminated, we can just stop location manager for further updating locations and can call the startMonitoringSignificantLocationChanges
self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoringSignificantLocationChanges()
When the app is killed, the location is grabbed from didFinishLaunching
method's launchOptions?[UIApplicationLaunchOptionsKey.location]
if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
//You have a location when app is in killed/ not running state
}
Make sure to keep BackgroundModes On for Location Updates
Also make sure to ask for locationManager?.requestAlwaysAuthorization()
by using the key
<key>NSLocationAlwaysUsageDescription</key>
<string>Allow location</string>
in your Info.plist
There can be a third solution by taking 2 LocationManagers simultaneously.
- For region
- Significant Location Changes
As using significantLocationChanges
Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.
as per the give Apple Doc
So it totally depends on your requirements as the location fetching depends on many factors like the number of apps opened, battery power, signal strength etc when the app is not running.
Also keep in mind to always setup a region with good accuracy.
I know that this will not solve your problem completely but you will get an idea to move forward as per your requirements.