iOS Geofence CLCircularRegion monitoring. locationManager:didExitRegion does not seem to work as expected

前端 未结 9 778
陌清茗
陌清茗 2020-11-28 03:09

I am currently trying to get my app to monitor particular regions using CoreLocation however I am finding that it does not seem to work as expected, it seems to

9条回答
  •  南笙
    南笙 (楼主)
    2020-11-28 03:40

    Based on @Nevan's answer, which indicated some sort of coverage in WWDC 2013 307 (which didn't directly address this), I came up with a reasonable solution to getting < 10m accuracy for the arrival to a location, though I have a feeling that implementing -(void)locationManager:didVisit: might make this more battery-conservative, but would provide less frequent updates.

    First, have some regions with 0..150m radius, and start monitoring. Doesn't really matter, as the system seems to trigger these at around 150~200m:

    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(location.lat, location.lng) radius:50 identifier:location.name];
    [_locationManager startMonitoringForRegion:region];
    

    Then, implement

    -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
        for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
            if ([enteredRegion.identifier isEqualToString:region.identifier]) {
    
                self.locationManager.activityType = CLActivityTypeFitness;
                self.locationManager.distanceFilter = 5;
                [self.locationManager startUpdatingLocation];
    
                break;
            }
        }
    }
    

    The system will start monitoring and reporting to your delegate a stream of locations, even if your app is suspended (need UIBackgroundModes to include location array element).

    To check if one of those locations is within the centre of one of your regions, Implement:

    -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
        CLLocation *firstLocation = [locations firstObject];
        CGFloat const DESIRED_RADIUS = 10.0;
    
        CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:firstLocation.coordinate radius:DESIRED_RADIUS identifier:@"radiusCheck"];
    
        for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
            if ([circularRegion containsCoordinate:enteredRegion.center]) {
                [_locationManager stopUpdatingLocation];
                NSLog(@"You are within %@ of %@, @(DESIRED_RADIUS), enteredRegion.identifier);            
                break;
            } else if ([enteredRegion containsCoordinate:circularRegion.center]) {
                NSLog(@"You are within the region, but not yet %@m from %@", @(DESIRED_RADIUS), enteredRegion.identifier);
            }
        }
    }
    

    You'll also want to implement:

    -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
        [_locationManager stopUpdatingLocation];
    }
    

提交回复
热议问题