CoreLocationManager never pauses?

2020-02-04 ios swift core-location

Trying to get my app to use less power, it's tracking location always in the background but I'd like for it automatically pause so I can turn on region watching and use that to resume precise location monitoring once the user moves around a bit.

I've had the app on for half an hour now and the location service is not pausing. I think this has been the case since Apple changed location stuff in iOS 13? I'm not really sure. All the documentation I can find online seems extremely outdated.

Any advice is greatly appreciated, relevant code follows:

init() {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = 10
        locationManager.activityType = .fitness
        locationManager.requestAlwaysAuthorization()
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.pausesLocationUpdatesAutomatically = true
        locationManager.showsBackgroundLocationIndicator = true
        locationManager.startUpdatingLocation()
    }
    func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager) {
        delegate?.paused(tracker: self)
        print("MT | LOCATION SERVICES PAUSED!") <---- NEVER GETTING CALLED (been running for 40 minutes now, no location updates, still going though?)
        // if not already, start region monitoring

    }
 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Collect data
        for location in locations {
           print("MT | New Location: \(location)")
        }
    }

Answers

I think it is quite clear from the docs that this the pause functionality does not work like that. First of all, there is no guarantee that the GPS hardware will pause at all, it depends on the type of activity as well as other activities in the system. It is up to iOS to decide when and if to pause location updates, the property is just a hint.

More important, your use case would not work since if it gets paused, the user would have to interact with your app manually to resume updates.

Apple mentions your case specifically and recommends reducing the accuracy of location updates so it is only using cell tower triangulation instead of GPS (see docs above).

So, instead of using pausesLocationUpdatesAutomatically = true, you could do desiredAccuracy = kCLLocationAccuracyThreeKilometers.

To quote Apple,

[...] consider disabling this property and changing location accuracy to kCLLocationAccuracyThreeKilometers when your app moves to the background. Doing so allows you to continue receiving location updates in a power-friendly manner

Doesn't this cover your use case?

I wouldn't rely on connecting to Xcode. Xcode is generally greedy. It doesn't want you to stop your debugging. So it never puts the app in a suspended state.

The callback of locationManagerDidPauseLocationUpdates is somewhat identical to your app being suspended which Xcode prevents.

The way I would test this is to use os.log. Then log the outputs to your Mac's console app. See here.


Just make sure the app is not launched from you running from Xcode. I'd rather disconnect your device from Xcode, kill the app. Disconnect your device from Xcode. Then just tap on the app icon again. That way Xcode cannot intervene.

The issue is caused by your desired accuracy.

You are setting the accuracy to the best, which will make your application run continuously, so it will never pause in any iOS versions.

Furthermore, in a practical test whether it is pausing or not, change the accuracy to kCLLocationAccuracyHundredMeters. It will definitely pause. You can change the filter accuracy as you need for the next update.

Do you think maybe your activityType is preventing the location services to pause?

activityType

The location manager uses the information in this property as a cue to determine when location updates may be automatically paused. Pausing updates gives the system the opportunity to save power in situations where the user's location is not likely to be changing.

.fitness

This activity might cause location updates to be paused only when the user does not move a significant distance over a period of time.


I don't know what your particular use case is but, have you considered using the following function for background location tracking?

startMonitoringSignificantLocationChanges()

You may also try a mix of both, turning on significant location changes for day to day use and allowsBackgroundLocation when doing something like tracking a run, etc.

Related