CLLocationManager only monitors regions the first

2019-05-31 12:54发布

I have an iOS app which is a tabbed application, with 3 view controllers, all of which need to know when the phone enters specific geographical regions.

The regions which we monitor for are supplied at run time over a web interface, so we need to periodically clear the regions that the CLLocationManager is monitoring for and add new ones. The CLLocationManager object is a member variable of a singleton class which manages the connection with the web server as well.

The problem that I have is that when the application is first installed, the region monitoring works fine. But the first time I try to run it after that first time, the region monitoring does not work.

I can see this on both the actual handset and the iOS simulator.

On receipt of the mesasge from the server which contains the region details, we run the following code:

-(void) initialiseLocationManager:(NSArray*)geofences
{
    if(![CLLocationManager locationServicesEnabled])
    {
        NSLog(@"Error - Location services not enabled");
        return;
    }
    if(self.locationManager == nil)
    {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
    }
    else
    {
        [self.locationManager stopUpdatingLocation];
    }
    for(CLRegion *geofence in self.locationManager.monitoredRegions)
    {
        //Remove old geogate data
        [self.locationManager stopMonitoringForRegion:geofence];
    }
    NSLog(@"Number of regions after cleanup of old regions: %d", self.locationManager.monitoredRegions.count);
    if(self.locationManager == nil)
    {
        [NSException raise:@"Location manager not initialised" format:@"You must intitialise the location manager first."];
    }
    if(![CLLocationManager regionMonitoringAvailable])
    {
        NSLog(@"This application requires region monitoring features which are unavailable on this device");
        return;
    }
    for(CLRegion *geofence in geofences)
    {
        //Add new geogate data

        [self.locationManager startMonitoringForRegion:geofence];
        NSLog(@"Number of regions during addition of new regions: %d", self.locationManager.monitoredRegions.count);
    }
    NSLog(@"Number of regions at end of initialiseRegionMonitoring function: %d", self.locationManager.monitoredRegions.count);
    [locationManager startUpdatingLocation];
}

I have tried calling [locationmanager stopUpdatingLocation] in various places, in particular in various places in the AppDelegate.m file (applicationWilLResignActive, applicationDidEnterBackground, applicationWillTerminate), but none of them seem to help. Either way, when I build my application and add a GPX file to simulate locations, the simulator correctly picks up the regions being sent by the web interface. The second time I run the program, the regions are not picked up. When I reload the GPX file, it works again, but from the second time onwards, it doens't work any more.

According to the API documentation, the CLLocationManager keeps a record of regions even on termination (which is why I clear down the regions which we monitor for), but my guess is that my initialisation routine is good for the first time the app runs, but calls things that shouldn't be called from the second time onwards. Also, the clearing down process doesn't always seem to work (the NSLog statement often shows the CLLocationManager clearing down to 0 regions, but not always).

Any ideas why this isn't working?

1条回答
地球回转人心会变
2楼-- · 2019-05-31 13:32

So lets clean this up a little bit

You dont need to call startUpdatingLocation and stopUpdatingLocation when using region monitoring. Those activate the standard location tracking sending messages to the delegate callback locationManager:didUpdateLocations:. Region tracking apps implement these delegate callbacks:

– locationManager:didEnterRegion:
– locationManager:didExitRegion:

Also its very unlikely that location services will become disabled in the course of this method and you should make sure its not possible to get rid of the 'locationManager' from a background thread. Therefore we dont need to check them twice.

As you are region monitoring its best to make sure you have region monitoring available with + (BOOL)regionMonitoringAvailable. Also best to check the location permissions with + (CLAuthorizationStatus)authorizationStatus at some point and react appropriately.

As per this blog post it seems you also need to have

UIBackgroundModes :{location}
UIRequiredDeviceCapabilities: {location-services}

in your apps info.plist for this all to work correctly.

If you have more information about the mode of failure i can come back with some more specific advice :)

查看更多
登录 后发表回答