didExitRegion not being called, loops didEnterRegion - ios

I am fairly new to iOS Development and I am trying to create an App that allows region monitoring. Similar to that of the iOS Reminders App.
I have my code to the point where I am starting monitoring for regions and it should notify me when I enter and leave a region. However, it only tells me when I am in the region. When I leave, it does not tell me.
Just so you know, I am testing this on my iPhone and definitely went outside of the 100m radius (I drove my car for 10 minutes away from my house). It kept looping messages saying I was in the region but never changed when I exited the region. I am really stumped as to where I am going wrong. Can anyone help? Also, just out of curiosity, as I am new to iOS development, am I going about this the correct way? Or is there a more efficient way of accomplishing this? Any advise, tutorials, howto's would be very much appreciated. Thanks guys! My code to start the region monitoring and methods are below. Let me know if you need any other code.
(IBAction)addRegion:(id)sender {
if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]) {
// Create a new region based on the center of the map view.
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(_mapView.centerCoordinate.latitude, _mapView.centerCoordinate.longitude);
region = [[CLCircularRegion alloc] initWithCenter:coord
radius:Radius
identifier:[NSString stringWithFormat:#"%f, %f", _mapView.centerCoordinate.latitude, _mapView.centerCoordinate.longitude]];
// Start monitoring the newly created region.
[_locationManager startMonitoringForRegion:(CLRegion *)region];
}
else {
NSLog(#"Region monitoring is not available.");
}
}
(IBAction)stopMonitoringRegion:(id)sender {
[_locationManager stopMonitoringForRegion:(CLRegion *)region];
}
(void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)reg {
if (state == CLRegionStateInside) {
//call didEnterRegion
//[_locationManager stopMonitoringForRegion:region];
[self locationManager:_locationManager didEnterRegion:region];
}
if (state == CLRegionStateOutside) {
//call didExitRegion
//[_locationManager stopMonitoringForRegion:region];
[self locationManager:_locationManager didExitRegion:region];
}
}
(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"didFailWithError: %#", error);
}
(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//requestStateForRegion
if (region == nil) {
//do nothing
NSLog(#"didUpdateToLocation %# from %#", newLocation, oldLocation);
}else{
[_locationManager requestStateForRegion:region];
NSLog(#"didUpdateToLocation %# from %#", newLocation, oldLocation);
}
}
(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"didEnterRegion %# at %#", region.identifier, [NSDate date]);
}
(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"didExitRegion %# at %#", region.identifier, [NSDate date]);
}
(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(#"monitoringDidFailForRegion %#: %# Error: %#", region.identifier, [NSDate date], error);
}

Related

didRangeBeacons call back always triggered with empty array of beacon

I'm using core location library in iOS for finding beacons, I'm in beacon region and the didRangeBeacons callback is triggering but it is always returning an empty array of beacons.
Please find the attached sample code. I have beacon immediate to iPhone, but still, beacon region state is inside when app opened and immediately it is changed to outside state and we are getting an empty array in didRangeBeacons. I have included both NSLocationWhenInUseUsageDescription. The NSLocationAlwaysUsageDescription keys are in the info.plist. The application has location permission set to "always". I'm using both Estimote and Kontakt beacons. OS version is iOS 11.2.6, Device iPhone 5s, Xcode 9.2.
#import "CoreLocationViewController.h"
#interface CoreLocationViewController ()
{
CLLocationManager *locationManager;
CLBeaconRegion *beacon_region;
}
#end
#implementation CoreLocationViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"CoreLocationViewController viewDidLoad");
NSUUID *ProximityUUID = [[NSUUID alloc] initWithUUIDString:#"b94f62c8-1af4-11e8-accf-0ed5f89f718b"];
beacon_region = [[CLBeaconRegion alloc] initWithProximityUUID:ProximityUUID identifier:#"abqwercds"];
[beacon_region setNotifyEntryStateOnDisplay:YES];
[beacon_region setNotifyOnExit:YES];
[beacon_region setNotifyOnEntry:YES];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
if ([CLLocationManager locationServicesEnabled]){
NSLog(#"Location Services Enabled");
if(IS_OS_8_OR_LATER){
NSLog(#"We are in LocationServicesRequestViewController IS_OS_8_OR_LATER");
NSUInteger code = [CLLocationManager authorizationStatus];
NSLog(#"CLLocationManager authorizationStatus %lu",(unsigned long)code);
if (code == kCLAuthorizationStatusNotDetermined) {
NSLog(#"kCLAuthorizationStatusNotDetermined");
[locationManager requestAlwaysAuthorization];
}
}else{
NSLog(#"We are in LocationServicesRequestViewController IS_OS_8_BELOW");
}
}else{
NSLog(#"authorizationStatus ");
}
}
#pragma mark Location Manager Delegate methods
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
NSLog(#"locationManager Error %#",error);
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
NSLog(#"Status of location service is %d",status);
if ((status == kCLAuthorizationStatusAuthorizedAlways) || (status == kCLAuthorizationStatusAuthorizedWhenInUse)){
NSLog(#"location service status changed 1");
[locationManager startMonitoringForRegion:beacon_region];
[locationManager requestStateForRegion:beacon_region];
}else{
NSLog(#"location service status changed 2");
}
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
NSLog(#"CLLocationManager Beacon Region State Determine ");
switch (state) {
case CLRegionStateUnknown:
{
NSLog(#" CLLocationManager Region state is unknown %#",region);
[locationManager stopMonitoringForRegion:beacon_region];
break;
}
case CLRegionStateInside:
{
NSLog(#" CLLocationManager Region state is In-Side %#",region);
[locationManager startRangingBeaconsInRegion:beacon_region];
}
case CLRegionStateOutside:
{
NSLog(#" CLLocationManager Region state is Out-Side %#",beacon_region);
[locationManager stopMonitoringForRegion:beacon_region];
break;
}
}
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
NSLog(#" CLLocationManager Enter into Region %#",region);
[locationManager startRangingBeaconsInRegion:beacon_region];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"didExitRegion location manager %#",region );
[locationManager stopMonitoringForRegion:beacon_region];
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{
NSLog(#"CLLocationManager Beacon Monitoring Started for the region %#",region);
}
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error{
NSLog(#"CLLocationManager Monitoring of beacon region %# is failed, Error %#",region,error);
}
-(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error{
NSLog(#"CLLocationManager ranging of beacon region %# is failed, Error %#",region.proximityUUID,error);
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region{
NSLog(#"beacons %#",beacons);
}

stopMonitoringForRegion is not removing the region

My app successfully entering in this delegate method
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"didEnterRegion = %#", region.identifier);
[self.clm stopMonitoringForRegion:region];
}
but stopMonitoringForRegion is not removing the region, Why?

Can't get Region Monitoring to function

After trying for a while using Apple's documentation, Stackoverflow, Google, I still can't get a simple UIAlertView to show up when I enter or exit a region I am monitoring.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
[locationManager requestAlwaysAuthorization];
for (CLRegion *monitored in [self.locationManager monitoredRegions])
[locationManager stopMonitoringForRegion:monitored];
CLLocationCoordinate2D coord;
coord.latitude = 31.521603;
coord.longitude = 33.01190;
CLCircularRegion *region = [[CLCircularRegion alloc]initWithCenter:coord radius:20 identifier:#"work"];
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
[self showMessage:[NSString stringWithFormat:#"EnterRegion: %#",region.identifier] andMessage:#"Welcome Home" andButton:#"Ok"];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
[self showMessage:[NSString stringWithFormat:#"ExitRegion: %#",region.identifier] andMessage:#"Bye Bye" andButton:#"Ok"];
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Now monitoring for %#", region.identifier);
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error{
[self showMessage:#"msg" andMessage:[NSString stringWithFormat:#"Region Failed:%#",region.identifier] andButton:#"ok"];
}
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
[self showMessage:[NSString stringWithFormat:#"Did Determine State: %#. state:%#",region.identifier, (state == CLRegionStateUnknown) ? #"Unknown" : (state == CLRegionStateInside) ? #"INSIDE" : #"OUTSIDE"] andMessage:#"Determined" andButton:#"Ok"];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ }
showMessage is just a UIAlertView popping to the user.
sometimes I get monitoringDidFailForRegion when I set up the region sometimes I don't.
I was thinking if I should mark my app as using "Background Modes" for Location Updates, but this has not changed a thing. Seems like it should work, but I can never get didEnterRegion nor didExitRegion to be called.
I should point out that I updated the info.plist with the required keys:
<key>NSLocationAlwaysUsageDescription</key>
<string>Location is required for geofence</string>
Background app refresh is set to On, locations enabled. Testing outside, physically, I can't get the functions to be called.
What is it that can be wrong here? is 20 meters too short to define a region?
Could it be that region monitoring is not working for an app that is on the foreground? silencing the callbacks?

locationManager didExitRegion or locationManager didEnterRegion never called

- (void)viewDidLoad
{
[super viewDidLoad];
if([CLLocationManager locationServicesEnabled]){
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
CLLocationCoordinate2D companyCenter;
companyCenter.latitude = 23.126272;
companyCenter.longitude = 113.395568;
CLRegion* fkit = [[CLCircularRegion alloc] initWithCenter:companyCenter
radius:500 identifier:#"fkit"];
[self.locationManager startMonitoringForRegion:fkit];
}else{
NSLog(#"not support");
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Error : %#",error);
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"Region monitoring failed with error: %#", [error localizedDescription]);
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(nonnull CLRegion *)region
{
NSLog(#"Entered Region - %#", region.identifier);
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(nonnull CLRegion *)region
{
NSLog(#"Entered Enter Region - %#", region.identifier);
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Started monitoring %# region", region.identifier);
}
Above is my code. I run in simulator without location,and then set custome location(23.126272,113.395568) in Debug ->location item , and it never call didEnterRegion delegate . anyone can help me ?
PS:my Xcode is 7.1.1, and Console log "Started monitoring fkit region"
You are missing a few steps. You have to add an entry to your info.plist declaring that you want to use location services while your app is in the foreground, (Using the NSLocationWhenInUseUsageDescription key) and then you need to check to see if you have permission, and ask for it if you don't.
Do a search on the string "Requesting Permission to Use Location Services" in the Xcode docs for more information.
Add this line in didStartMonitoringForRegion
[self.locationManager requestStateForRegion:yourregion];

Do I need to startLocationUpdates when registering for regions ios?

In my app I have registered some CLRegions. My whole functionality lies in these functions:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Entered Region - %#", region.identifier);
[self showRegionAlert:#"Entering Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Exited Region - %#", region.identifier);
[self showRegionAlert:#"Exiting Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Started monitoring %# region", region.identifier);
}
This function exists in my code, but I do not do anything inside here:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Location Update:%#",[NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude, newLocation.coordinate.longitude]);
}
My question is this:
Is this initialisation necessary?
- (void)initializeLocationUpdates {
[_locationManager startUpdatingLocation];
}
when you only want to account for regions?
No, but you do have to call startMonitoringForRegion: for each of the regions you want to monitor. Like this:
CLRegion *region = // Set up your region
self.locationManager.delegate = self; // Make sure you are set as the location manager's delegate
[self.locationManager startMonitoringForRegion: region]; // Start monitoring the region
See the startMonitoringForRegion: doc on this page
If you're only interested in being notified when entering / leaving regions, it is sufficient to invoke startMonitoringForRegion:. Check out Staying on Track with Location Services (WWDC 2012 Session 303 (Developer Account needed to sign in)).
It might be worth noting that you can monitor 20 regions at most - as stated in the API documentation.

Resources