In my app, I am using geofencing to perform an action when the user enter or leaves a specified location. The geofencing (CLMonitor)
is active permanently, and should work across multiple app sessions or after the device is restarted. It should also work after the app was minimized or terminated. This worked perfectly with iOS 17 and prior, but with iOS 18, things changed. As soon as iOS 18 dropped, users were informing me that the app does no longer perform the entry/exit action reliably (without me making any changes to the app). Most of the times, events are missed entirely. Sometimes, after the user opens or resumes the app, duplicate events are delivered and/or events with the current time instead of the correct time of entry/exit.
- I am making sure that the app has the "Always" location permission before geofencing is enabled
- The gefocence radius is between 20 and 500m, but even with the max. radius specified, the geofencing is unreliable
- For the same user and geofence, the entry/exit event is delivered occasionally, but not always
- I am currently not using
CLLocationManager.allowsBackgroundLocationUpdates
(even though it's documented as "Apps that receive location updates when running in the background must include the UIBackgroundModes key (with the location value) in their app’s Info.plist file") because it wasn't necessary on iOS 17 and in my tests, using it didn't yield any improvements
In my search for what could have caused this change, I found this WWDC video about location authorization: . It appears that with iOS 18, it is now required to have an active CLServiceSession
to ensure that location updates are delivered to my app. Even though the video is long (and I've watched it multiple times), some things are still unclear. For example, the docs state:
If your app actively receives and processes location updates and terminates, it should restart those APIs upon launch in order to continue receiving updates.
Also, in the video it is stated that:
... So your job, ..., is to make sure that your process launch logic knows what features it has been tasked with pursuing, and re-takes session objects...
But on the other hand it's also said that:
you can only start holding one (a CLServiceSession) when your app is in the foreground
and also
... CLMonitor.events won’t yield results when it is not in use, unless a session which was started in the foreground, ....
To summarize my questions, for the geofencing to work as described above:
- when exactly do I need to create a
CLServiceSession
if the app is launched into the backgorund? Immediately in the applicationDidFinishLaunching method, even though the app is still in the background (applicationState isbackground
)? Or later on, when the app is opened again by the user, e.g. in applicationDidBecomeActive (andapplicationState
isactive)?
- do I need to specify the background mode capability as noted in the Handling location updates in the background article?
- do I need to create a
CLBackgroundActivitySession
as noted in the Handling location updates in the background article? - does it matter, which of the four initializer methods I am using to create the
CLServiceSession
(withCLServiceSessionAuthorizationRequirementAlways
)? - does it matter if I specify
NSLocationRequireExplicitServiceSession
in theInfo.plist
or not when I already do ensure that the app has the "Always" location permission when the feature is being enabled - Does a CLServiceSession last indefinitely and should it only be invalidated once the user disables the feature?