Why Geofence tracking using Cllocationmanager delegate methods not calling - ios

Hiii,
I implemented Geo fences by using location manager.
Here i am creating regions
enter code here
In view did load i create object as
//for Geo fence tracking
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLLocationAccuracyBest;
[locationManager startMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
-(void)TraceGeofenceLocation{
for (int k=0; k< [self.chGeofenceType count]; k++) {
NSString *chTracLati = [NSString stringWithFormat:#"%f",[[self.chGeofenceLatitudes objectAtIndex:k] doubleValue]];
NSString *chTracLong = [NSString stringWithFormat:#"%f",[[self.chGeofeceLongitudes objectAtIndex:k] doubleValue]];
NSString *chTracRadius = [NSString stringWithFormat:#"%f",[[self.chGeofenceRadius objectAtIndex:k] doubleValue]];
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(chTracLati.doubleValue, chTracLong.doubleValue);
if ([[self.chGeofenceType objectAtIndex:k] intValue] == 1) {
region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:chTracRadius.doubleValue identifier:#"Restricted"];
}
else if ([[self.chGeofenceType objectAtIndex:k] intValue] == 2){
region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:chTracRadius.doubleValue identifier:#"SafeZone"];
}
else{
region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:chTracRadius.doubleValue identifier:#"Curfew"];
}
[region setNotifyOnEntry:YES];
[region setNotifyOnExit:YES];
[locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest];
}
}
I tested in my delegate methods if any region it will enter or not.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
locationnew = locations.lastObject;
self.Latit=[NSString stringWithFormat:#"%f", locationnew.coordinate.latitude];
self.Longi=[NSString stringWithFormat:#"%f",locationnew.coordinate.longitude];
Speed = [[NSString stringWithFormat:#"%f",[locationnew speed]] floatValue];
NSLog(#"Speed :%f Latitude :%# Longitude :%#",Speed,self.Latit,self.Longi);
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if ([region.identifier isEqualToString:#"Restricted"]) {
[self sendNotificationtoServerwithtype:#"1"];
}
else if ([region.identifier isEqualToString:#"Curfew"]){
[self sendNotificationtoServerwithtype:#"3"];
}
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
if ([region.identifier isEqualToString:#"SafeZone"]){
[self sendNotificationtoServerwithtype:#"2"];
}
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
if (state == CLRegionStateInside){
NSLog(#"is in target region");
}else{
NSLog(#"is out of target region");
}
}
My delegate method update locations are calling and i get in console,
but enter into region,exit from regions and did DetermineState are not calling...
Can anybody help me please.
Thanks In Advance

startUpdatingLocation and startMonitoringSignificantLocationChanges are mutually exclusive. If you want to do startMonitoringSignificantLocationChanges to look for geofences, make sure you call stopUpdatingLocation first.
Also be aware that geofence detection is not incredibly precise. On average, you can a resolution of hundreds of meters. I've found that didEnterRegion often take several minutes to be called, if at all.
NOTE: you are currently calling [locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest]; The problem with this is kCLLocationAccuracyBest is a really small area. (kCLLocationAccuracyBest codes for the value 1.0). That means you are asking the system to let you know when you enter an area with a diameter 1.0 meter. Since geofence detection has accuracy of hundreds of meters, this may never get called. Instead you should set the accuracy to something much lower: [locationManager startMonitoringForRegion:region desiredAccuracy:200.0];
Good luck.

Related

CoreLocation iOS9 storing Coordinates

I recently asked this question, not knowing of the changes made to CL in iOS 9. I am trying to store the user's current location and I have changed my code to reflect the new delegate methods in iOS 9, but didUpdateLocations is still never reached.
Here is the link to my original question: Latitude & Longitude Not Retrieved
And my updated code:
viewWillAppear
- (void)viewWillAppear:(BOOL)animated{
manager = [[CLLocationManager alloc] init];
manager.delegate = self;
if ([manager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[manager requestWhenInUseAuthorization];
}
[manager startUpdatingLocation];
}
didUpdateLocations
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations{
NSLog(#"Location: %#", locations);
CLLocation *currentLocation = locations.lastObject;
if (currentLocation != nil) {
float latitude = currentLocation.coordinate.latitude;
float longitude = currentLocation.coordinate.longitude;
NSLog(#"dLongitude : %f", longitude);
NSLog(#"dLatitude : %f", latitude);
}
else{ NSLog(#"ERROR");
}
}
check for
authorizationStatus and startUpdatingLocation
and
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
you can also go to settings ->privacy -> location services (turn on) -> select ur app and select while using.

Understanding iBeacons in iOS: didDetermineState and didEnterRegion events

Part one:
I have written the following code to monitor iBeacons. I would like to detect the didEnterRegion and didExitRegion event. However it never happens. Would you be able to take a look at the code and suggest what could be missing?
I use the Apple AirLocate sample code to configure one device as iBeacon and perform the following steps to test my code:
Steps:
compile and execute AirLocate sample code on device B
compile and execute this code on device A
in device B use AirLocate app to configure device as iBeacon choosing the following UUID: "74278BDA-B644-4520-8F0C-720EAF059935"
Results:
state inside message
Expected results:
state inside message
did enter region
Why is that?
Those are my plist entries:
Code:
#import "BeaconMonitoring.h"
#implementation BeaconMonitoring
- (instancetype)init
{
self = [super init];
if (self) {
self.locationManager = [[CLLocationManager alloc] init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.monitoredRegions = [[NSMutableArray alloc] initWithCapacity:10];
}
return self;
}
- (void) startRangingForBeacons{
NSLog(#"in startRangingForBeacons");
[self.locationManager startUpdatingLocation];
[self startMonitoringForRegion:[[NSUUID alloc] initWithUUIDString:#"74278BDA-B644-4520-8F0C-720EAF059935"] :#"b"];
}
- (void) startMonitoringForRegion:(NSUUID*)beaconUUID :(NSString*)regionIdentifier{
/**
Alternatively:
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:#"xxxx"
major:10
minor:20
identifier:#"name"]
**/
// Override point for customization after application launch.
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:regionIdentifier];
beaconRegion.notifyEntryStateOnDisplay = NO;
beaconRegion.notifyOnEntry = YES;
beaconRegion.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:beaconRegion];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
[self.monitoredRegions addObject:beaconRegion];
}
- (void) stopRangingForbeacons{
NSLog(#"in stopRangingForbeacons");
[self.locationManager stopUpdatingLocation];
for (int i=0; i < [self.monitoredRegions count]; i++) {
NSObject * object = [self.monitoredRegions objectAtIndex:i];
if ([object isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion * region = (CLBeaconRegion*)object;
[self.locationManager stopMonitoringForRegion:region];
[self.locationManager stopRangingBeaconsInRegion:region];
}
else{
NSLog(#"Serious error, should never happen!");
}
}
}
#pragma CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
[manager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
[self.locationManager startUpdatingLocation];
NSLog(#"You entered the region.");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
[self.locationManager stopUpdatingLocation];
NSDictionary * notificationData = #{ #"value" : #"exitedRegion"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"dataUpdate" object:nil userInfo:notificationData];
NSLog(#"You exited the region.");
// [self sendLocalNotificationWithMessage:#"You exited the region."];
}
- (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
NSLog(#"did determine state");
switch (state) {
case CLRegionStateInside:
NSLog(#"state inside");
break;
case CLRegionStateOutside:
NSLog(#"state outside");
break;
case CLRegionStateUnknown:
NSLog(#"state unknown");
break;
default:
NSLog(#"Default case: Region unknown");
break;
}
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
NSLog(#"Did range %lu beacon in region %#", (unsigned long)[beacons count], region.identifier);
NSString * visibleInformation = [NSString stringWithFormat:#"(%lu)", (unsigned long)[beacons count]];
for (int i=0; i<[beacons count]; i++) {
CLBeacon *beacon = [beacons objectAtIndex:i];
if ([beacons count] == 1) {
NSNumber * distance = [NSNumber numberWithFloat:beacon.accuracy];
visibleInformation = [NSString stringWithFormat:#"%i-%i is %f", beacon.major.intValue, beacon.minor.intValue, distance.doubleValue];
}
else{
visibleInformation = [visibleInformation stringByAppendingString:[NSString stringWithFormat:#" %i-%i ", beacon.major.intValue, beacon.minor.intValue]];
}
}
}
#end
Part two:
I had a look at the AirLocate source code to understand if there was something that I had to trigger in the state inside message to get the monitoring working properly. However I found that the ** didDetermineState** method is implemented in the AppDelegate.
Why is that?
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
/*
A user can transition in or out of a region while the application is not running. When this happens CoreLocation will launch the application momentarily, call this delegate method and we will let the user know via a local notification.
*/
UILocalNotification *notification = [[UILocalNotification alloc] init];
if(state == CLRegionStateInside)
{
notification.alertBody = NSLocalizedString(#"You're inside the region", #"");
}
else if(state == CLRegionStateOutside)
{
notification.alertBody = NSLocalizedString(#"You're outside the region", #"");
}
else
{
return;
}
/*
If the application is in the foreground, it will get a callback to application:didReceiveLocalNotification:.
If it's not, iOS will display the notification to the user.
*/
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
Assumption: R = Region made by B and listened to by A
Case 1
IF A was started before B:
app A should tell you determine state for region R = outside
app A should run didEnter Region R
case 2
IF A was infact started after B:
it should only run determineState Region R = inside
the end. There is no 2 here because it never enters the range. it was started inside of it

region monitoring doesn't call didExitRegion unless conditions

I'm building an iOS 8 app that uses GeoFencing. I'm having some problems that I will explain later. But first, this is how I create a region and monitor it:
Variables in header file:
#property (nonatomic, strong) CLLocationManager *locationManager;
viewDidLoad:
// Initialize locationManager
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager requestAlwaysAuthorization];
// Set the delegate
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLLocationAccuracyBest;
Creating a region:
- (CLRegion*)mapDictionaryToRegion:(NSDictionary*)dictionary
{
NSString *title = [dictionary valueForKey:#"title"];
CLLocationDegrees latitude = [[dictionary valueForKey:#"latitude"] doubleValue];
CLLocationDegrees longitude =[[dictionary valueForKey:#"longitude"] doubleValue];
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);
CLLocationDistance regionRadius = [[dictionary valueForKey:#"radius"] doubleValue];
return [[CLRegion alloc] initCircularRegionWithCenter:centerCoordinate
radius:regionRadius
identifier:title];
}
Start monitoring it:
-(void)startMonitoringForDictionary:(NSDictionary *)dictionary
{
// Start monitoring for the supplied data
CLRegion *region = [self mapDictionaryToRegion:dictionary];
[self.locationManager startMonitoringForRegion:region];
}
Listening for region crossing:
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"Error: %#", error);
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"didEnterRegion");
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"exited region");
}
I've remembered these keys in my target info:
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
Problem:
Sometimes when I enter a region, it works flawless. Both didEnterRegion and didExitRegion is called like expected. But it appears as if I add the region while inside it, and then exit - it won't call didExitRegion. Only if it calls didEnterRegion first.
What I'm asking:
Could someone please explain the "rules" for region monitoring and how the device manages it, reports it, wakes app, etc? Also, I read in the documentation that I shouldn't expect updates more frequently than every 5 minutes. (This thing I'm making to practice calculates how long you've spent inside a region) - what if the user enters then exists quickly - then didExitRegion will never be called until I enter again?
Thanks!
Erik
You must call requestState immediately when calling startMonitoringForRegion

Testing a fake current location on iOS Simulater is not working

I have been trying to fake my location in the iOS simulator but the methods I have been reading about are not working. I have used the debugger to set my fake location, and have made a custom location in Debug->Location->Custom Location, yet I still log 0.000 0.000 for lat and long.
I'm using this code to find current location.
- (IBAction)currentLocationButtonPressed:(UIButton *)sender
{
//Search for pubs and bars in current location.
//Push to tableViewController
NSLog(#"current location Pressed.");
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyBest; // Best accuracy
[locationManager startUpdatingLocation];
NSLog(#"%#",[self deviceLocation]);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSLog(#"Latitude: %f Longitude: %f", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude);
}
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude];
}
The delegate is set and I am requesting authorization.
- (void)viewDidLoad {
[super viewDidLoad];
searchLocationTextField.delegate = self;
locationManager.delegate = self;
locationManager = [[CLLocationManager alloc]init];
[locationManager requestWhenInUseAuthorization]; // For foreground access
[locationManager requestAlwaysAuthorization]; // For background access
}
Set locationManager delegate to after allocating it.
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager:didUpdateToLocation:fromLocation: delegate method is deprecated, use locationManager:didUpdateLocations: instead.
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *currentLocation = [locations lastObject];
NSLog(#"Latitude: %f Longitude: %f", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude);
}

ibeacons sending rssi value of 0

I have 8 iBeacons and i gave them all the same proximityUUID and different major minor values
however, when i try to use the phone to find the beacons, some of them send "rssi" value of 0
why is that ?
#implementation CLBeacon(description)
-(NSString *)stringProximity{
switch (self.proximity) {
case CLProximityUnknown:
return #"Unknown";
case CLProximityImmediate:
return #"less than 0.5 meters away";
case CLProximityNear:
return #"0.5<distance<4 meters away";
case CLProximityFar:
return #"more than 4 meters away";
}
return #"";
}
-(NSString *)UUIDString{
NSMutableString *string = [[[self proximityUUID]UUIDString]mutableCopy];
[string replaceOccurrencesOfString:#"-" withString:#"-\n" options:0 range:NSMakeRange(0, [string length])];
return string;
}
-(NSString *)describe{
NSString *contents = [NSString stringWithFormat:#"proximityUUID:%#\nmajor:%#\nminor:%#\naccuracy:%f\nproximity:%#\nrssi:%ld",[self UUIDString],[self major],[self minor],[self accuracy],[self stringProximity],[self rssi]];
return contents;
}
#end
#implementation WBBeaconManager
-(id)init{
self = [super init];
if(self){
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self initRegion];
[self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
- (void)initRegion {
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACONUUID];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:BEACONIDENTIFIER];
[self.locationManager startMonitoringForRegion:self.beaconRegion];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Beacon Found");
[self makeText:[NSString stringWithFormat:#"entered region:%#",region.identifier ]];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
[self makeText:[NSString stringWithFormat:#"entered region: %#",region.identifier]];
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Left Region");
[self makeText:[NSString stringWithFormat:#"left region:%#",region.identifier ]];
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
[self makeText:[NSString stringWithFormat:#"left region: %#",region.identifier]];
// self.beaconFoundLabel.text = #"No";
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
CLBeacon *beacon = [beacons firstObject];
for(CLBeacon *b in beacons){
LogInfo(#"%#",[b describe]);
}
// if(beacon.proximity == CLProximityNear || beacon.proximity == CLProximityImmediate){
[self makeText:[beacon describe]];
// }
}
-(void)dealloc{
[self.locationManager stopMonitoringForRegion:self.beaconRegion];
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}
#end
and here is the log output:
proximityUUID:73A7B094-35DD-4B36-A0AA-F11C62E9B4B0
major:0
minor:3
accuracy:-1.000000
proximity:Unknown
rssi:0
The RSSI is the "received signal strength of the beacon, measured in decibels." Sometimes a beacon listener will find a beacon, but can't actually determine its RSSI. This is why your accuracy is negative. The RSSI is also an average of "the values of the samples received since the range of the beacon was last reported to your app."
A negative value in this property signifies that the actual accuracy could not be determined.
In this case, you are probably about to exit the beacon region, or you are right on the fringe of its range.
Seems like RSSI is a mean value computed using x samples, when the iPhone/iPad does not receive a minimum amount of samples for this beacon it doesn't compute the mean rssi value neither the accuracy, and you got an Unknown proximity.
I made my own sampler and used average rssi for 5 seconds and ignored zero value if average rssi is not zero because it must be noise data.

Resources