In my application I want do geofencing. I have list of locations, for which I am setting geofencing regions. All location have radius 100m. Following is the code to set Region:
CLLocationCoordinate2D cord;
cord.latitude = [location.latitude doubleValue];
cord.longitude = [location.longtitude doubleValue];
CLLocationDistance regionRadius = location.radius;
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:cord radius:regionRadius identifier:[NSString stringWithFormat:#"%d",location.locId]];
[appDelegate.locationManager startMonitoringForRegion:region];
My problem is that, its not working properly. For debugging, in didEnterRegion delegate added distance calculation in between current location and region location some times this distance is more then 1500m.
Following is the code to calculate distance between current location and region location:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
CLLocation *loc1 = locationManager.location;
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:region.center.latitude longitude:region.center.longitude];
double dist = [loc1 distanceFromLocation:loc2];
}
Any idea, why -locationManager:didEnterRegion: get triggered such a wrong way?
This is a glitch in iOS Region Monitoring and I have faced the similar issue with Geofencing and I have found a way to solve that problem.
I have posted the question here and I have answered myself, I have a blog post on that as well:-
Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time
iOS Region Monitoring and Location Manager
Related
I have created a sample application for tracking GPS locations based on geofencing. First of all I have created one geofence and added the same to monitoring, using same location placed a circular overlay on MapView.
CLLocationCoordinate2D centerCoordinate1 = CLLocationCoordinate2DMake(23.518192, 72.337122);
CLCircularRegion *region1 =[[CLCircularRegion alloc] initWithCenter:centerCoordinate1 radius:100 identifier:#"Location First"];
NSLog(#"%#",[region1 description]);
region1.notifyOnEntry=YES;
region1.notifyOnExit=YES;
[self.locationManager startMonitoringForRegion:region1];
NSLog(#"Started Monitoring- %#", [region1 description]);
[self.mapview setShowsUserLocation:YES];
[self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
// create circle around monitor region and check if worker location is changed
MKCircle *circle1 = [MKCircle circleWithCenterCoordinate:centerCoordinate1 radius:100];
[self.mapview addOverlay:circle1];
Now, I am testing different co-ordinates in simulator by changing the simulator location by Debug->Location->Custom Locations.
If I am change major lat-long then it will call the region enter/exit methods, but if I am checking with near by locations by +/- with 10 or 20 points in latitude and longitude repetatively.
First Image which is inside the GeoFence
Another Image which is outside the GeoFence
Another image is visually outside the GeoFence, but while setting up this latitude and longitude it does not call region exit method.
Below are the region monitoring methods
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region;
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
I am adding 4 to 5 regions to monitor at the same time.
Any help would be highly appreciated.
I am using simulator and changing the location to simulate the movement of device.
The problem that I have figured out is that:
In the following code, when I try to print the latitude and longitude values, the value are rounded off to 6 decimal digits(43.825885,-75.839785) while the original values that I enter in the simulator(Debug->Location) is 43.82588498,-75.83978498. (For these initial values, the didUpdateLocations delegate gets called)
Now the next location(Just next to the previous location) that I enter is 43.82499145,-75.84050195 which I must get 43.824991,-75.840502. But this time the didUpdateLocations delegate doesn't get called.
But when I now give 43.82110323,-75.85291386 (rounded to 43.821103,-75.852914), this time the didUpdateLocation delegate is called.
(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocationCoordinate2D coordinate = [[locations lastObject] coordinate];
NSString *latitude = [NSString stringWithFormat:#"%f", coordinate.latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", coordinate.longitude];
NSLog(#"here Latitude : %#", latitude);
NSLog(#"here Longitude : %#",longitude);
}
The following are my locationManager properties:
_locationManager = [[CLLocationManager alloc] init];
[_locationManager setDelegate:self];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[_locationManager setDistanceFilter:300];
[_locationManager startUpdatingLocation];
[_locationManager startUpdatingHeading];
This is my mapView object's setup:
self.mainMapView.delegate=self;
[self.mainMapView setShowsUserLocation:YES];
Is this behavior because the OS is rounding off the Lat/Lon values? Or is it because I am using the simulator(which I don't think should be the problem because when I read similar questions, people have mentioned that if you simulate location then there shouldn't be any problem)?
I don't have an iOS device. Is it still possible that didUpdateLocation may work correctly on an actual device?
I am not able to figure out the bug here. I want the didUpdateLocations delegate to be called every time a slightest location update is made. Kindly guide me.
Try removing your setDistanceFilter and letting locationManger use the default (kCLDistanceFilterNone). The distance filter tells your location manager to call didUpdateLocations only when the device has moved that amount or beyond. So, in your case, it will update the location every 300 meters.
The first thing you need to do is to add one or both of the following keys to your Info.plist file:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Next you need to request authorization for the corresponding location method, WhenInUse or Background. Use one of these calls:
[self.locationManager requestWhenInUseAuthorization]
[self.locationManager requestAlwaysAuthorization]
// Check for iOS 8
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
I have an application working on iOS devices getting constantly the current latitude and longitude from the device. I would like to show an alert when the user reaches a certain lon/lat.
Here is the long to be reached : 2.39364456
Here is the lat to be reached : 48.84185814
When the user reaches this point, he should get an alert.
Unfortunately it doesn't work since the user doesn't always get to this exact point.
What I would like to do is : if you are NEAR to this point, in a certain range defined, then we pop up the alert.
I have no idea how to do this. I tried to implement long/lat to UTM converter and then try to work with UTM format but it was a failure.
Is it possible to work with the lon/lat's numbers which are after the comas to make a "range" to be in so the pop up shows ?
Thanks for reading and thanks in advance for your help ;)
Sounds like you are looking for the region monitoring functionality that comes in Core Location in iOS.
Here is a related question that talks about that.
And here is some Apple sample code.
And the latest Apple documentation that talks about Region Monitoring.
When your app gets into the region you're watching, your app gets called with the CLLocationManager delegate "locationManager:didEnterRegion:" method. And that is where you can fire your UIAlert from.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
CLLocation *locA = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.latitude longitude:currentLocation.coordinate.longitude];
}
CLLocation *locB = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
distance = [locA distanceFromLocation:locB];
if(distance<yourDesiredDiustance)
{
show Alert
}
}
You have 2 locations, aCLLocationA which is position defined by you, and aCLLocationB user location which get's updated. Now what you do:
Step 1
Find the distance by using this code between points on Map:
CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];
Step 2
if(distance<=yourRange)
{
//You have to show popup, because your location is in range with that point
}
I am running this off my iPhone 4 device.
First, here is the relevant code:
-(void)applicationDidBecomeActive:(UIApplication *)application
{
CLLocationDegrees latitude = 45.50568;
CLLocationDegrees longitude = -73.21352;
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude);
CLLocationDistance radius = 200.0;
CLRegion *myRegion = [[CLRegion alloc] initCircularRegionWithCenter:center radius:radius identifier:#"region1"];
[locationManager startMonitoringForRegion:myRegion];
}
But at no point whatsoever does didStartMonitoringForRegion get called, not even monitoringDidFailForRegion gets called.
What am I doing wrong? My device supports regional monitoring, I can't see what the problem is.
I have a MKMapView on my app. This is iOS6.
-(void)viewDidLoad
{
.....
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"Update locations is hit");
NSLog(#"379 the locations count is %d",locations.count);
CLLocation *obj = [locations lastObject];
NSLog(#"the lat is %f", obj.coordinate.latitude);
NSLog(#"the long is %f", obj.coordinate.longitude);
NSLog(#"the horizontal accuracy is %f",obj.horizontalAccuracy);
NSLog(#"the vertical accuracty is %f",obj.verticalAccuracy);
if (obj.coordinate.latitude != 0 && obj.coordinate.longitude != 0)
{
CLLocationCoordinate2D currrentCoordinates ;
currrentCoordinates.latitude = obj.coordinate.latitude;
currrentCoordinates.longitude = obj.coordinate.longitude;
}
....more computation
[locationManager stopUpdatingLocation];
}
When I first load the app, my location is showing little far away. Some times miles away. I also have a reset location button and if I click that map shows correct location. This is what I have in reset location button click:
- (IBAction)btnResetLocationClick:(UIButton *)sender
{
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
}
So how do I make the app get the correct current location on load up itself. Is there a way for the app to tell the map to wait for few milliseconds and then update. Or any other idea? Please let me know. If you need more information, please ask. Thanks.
What you could do is to:
do not turn off location services in didUpdateLocations automatically, but rather;
turn off location services in didUpdateLocations only if you're sufficiently happy with the horizontalAccuracy; and
even if you don't get the desired accuracy, turn off location services after a certain amount of time has passed.
Thus, didUpdateLocations might look like:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
// do whatever you want with the location
// finally turn off location services if we're close enough
//
// I'm using 100m; maybe that's too far for you, but 5m is probably too small
// as you frequently never get that accurate of a location
if (location.horizontalAccuracy > 0 && location.horizontalAccuracy < 100)
[locationManager stopUpdatingLocation];
}
And then in viewDidLoad, turn if off after a certain period of time has passed (you might want to check some status variable that you set if you've already turned off location services):
-(void)viewDidLoad
{
.....
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 60.0 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[locationManager stopUpdatingLocation];
});
}
Original answer:
I don't see where you're updating your map to be around your location. I'd expect to see something like:
self.mapView.centerCoordinate = location.coordinate;
or like:
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location.coordinate, 300, 300);
[self.mapView setRegion:region];
I'd also suggest, rather than turning off location services immediately (since frequently the first few locations are not that accurate), leave it on for a bit and let it hone in on your location until the horizontalAccuracy and verticalAccuracy fall within a certain predetermined limit. Look at those accuracy figures for a few calls to didUpdateLocations and you'll see what I mean.
I originally thought you were getting a negative horizontalAccuracy at which point I suggested implementing didFailToLocateUserWithError because according to horizontalAccuracy, "A negative value indicates that the location’s latitude and longitude are invalid." Hopefully you get an error that describes what the issue is. Even if you're not currently getting a negative horizontalAccuracy, you might want to implement this method, just to make sure you're handling any errors correctly.
You can't make the GPS in the iPhone more accurate in your app, but you can check that the result is accurate before carrying on. Right now you're only checking the lat and long aren't 0, but if you check obj's horizontalAccuracy then you'll know when the location information is good enough. Don't stopUpdatingLoation until that happens.