This question already has answers here:
Update Location in Mapview Xcode
(2 answers)
Closed 7 years ago.
Hi i want to call the webservice whenever there is a location change of 50 meters(not less than this). I have tried using significant changes but it works for minimum 500 meters and startupdatelocations will call all the time. So How can i detect if the device moved 50 or 100 meters from the location.
I have used the distance filter as 50 meters as said in many stackoverflow questions. But it doesnt work before moving to 50 meters i got the location updates in device.
Here some one explained about distance filter - iphone core location: distance filter how does it work?
It's Very Easy.
First Write in your ViewDidload Method To alloc CLLocationManager.
Here i set 50M distance .
locationManager = [[CLLocationManager alloc] init];
//there will be a warning from this line of code
[locationManager setDelegate:self];
//and we want it to be as accurate as possible
//regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//set the amount of metres travelled before location update is made
[locationManager setDistanceFilter:50];
[locationManager requestAlwaysAuthorization];
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
So Every 50 Meter change Device This Method is called :
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (locations.count > 0) {
CLLocation *location = locations.lastObject;
User_latitude = [NSString stringWithFormat:#"%f",location.coordinate.latitude];
User_longitude = [NSString stringWithFormat:#"%f",location.coordinate.longitude];
NSLog(#"latitude = %f",location.coordinate.latitude);
NSLog(#"longitude = %f",location.coordinate.longitude);
[self webservice_UpdateLocation];
}
}
Related
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 am having a problem where it will sometimes take me 15 seconds or so to find my location. On the contrary, Google Maps will find my location within a few seconds, nearly every time. I am wondering if there is anyway I can speed up Core Location and CLLocationManager so that it finds the user location faster. Here is my setup
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.activityType = CLActivityTypeFitness;
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.locationManager startUpdatingLocation];
[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(checkAccuracy:) userInfo:nil repeats:YES];
For the CLLocationManagerDelegate I have:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// If the event is recent, do something with it.
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
[[NSNotificationCenter defaultCenter] postNotificationName:kLocationChanged object:nil];
}
}
The notification at the end changes the map view center. Any idea on this? am I missing something?
The problem is the accuracy. You are not getting values until the location accuracy is near 10 meters.I don't know about you spec., but personally I use a wider accuracy and when I get the first location I change the required accuracy on the location manager.
The documentation says that:
When requesting high-accuracy location data, the initial event
delivered by the location service may not have the accuracy you
requested. The location service delivers the initial event as quickly
as possible. It then continues to determine the location with the
accuracy you requested and delivers additional events, as necessary,
when that data is available.
but in my experience is not like that, if I set for good accuracy it takes more time to have the first location, probably because it needs to "power up" more resources (is just a guess).
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
It consumes more battery, but you will get more location updates. Be careful to filter signals of low accuracy and also to check timestamp of the GPS signal to ignore old updates.
{
...
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"myLocation1: %#",[locations lastObject]);
myLocation = [locations lastObject];
NSLog(#"myLocation2: %#",[locations lastObject]);
[manager stopUpdatingLocation];
[self doSomethingWithLocation];
}
Currently I'm in the location 40.000,40.000.
I'm closing my app and change location to 10.000,10.000
When entering the app again and running [locationManager startUpdatingLocation]; my log will show:
myLocation1: <+40.00000000,+40.00000000>
myLocation2: <+40.00000000,+40.00000000>
If I'll trigger [locationManager startUpdatingLocation]; again my log will show:
myLocation1: <+10.00000000,+10.00000000>
myLocation2: <+10.00000000,+10.00000000>
How can I call didUpdateLocations once and still get the current location?
Should I use another delegate?
I guess I could place stopUpdatingLocation inside doSomethingWithLocation and run doSomethingWithLocation after some sort of delay in order for the right location to be updated but I'm sure that's not the way it's meant to be.
Thanks
Leave the location manager running for a while (e.g. 30 seconds), setting a timer to tell it to stop. The location manager updates are like pancakes, the first one you get isn't always the best.
The first update you are seeing is likely a "stale" location, which was determined many minutes ago when location services were last powered up. Or it may be a very inaccurate location determined using cell-tower positioning, for example. If you just need to get the device's current location, using Core Location directly requires a good deal of code because you must handle these cases. (The CLLocationManager API appears to be built for apps that need continuous location updates, like turn-by-turn GPS navigation apps.)
Instead of using CLLocationManager directly, I suggest you take a look at using an open source component such as INTULocationManager which will handle all of this work for you and make it trivially simple to request one or more discrete requests for the device's current location.
In this case you should check timestamp of location. User does not move on such distances so quickly.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
if(fabs([location.timestamp timeIntervalSinceNow]) < 5)//seconds
{
myLocation = location;
manager.delegate = nil;
[manager stopUpdatingLocation];
[self doSomethingWithLocation];
}
}
I'm looking for an open source app or library to track user location in the background. Now I'm trying to do it with CLLocation and background tasks, but accuracy is not enough for my case. Could you explain, how apps, like "moves", "runkeeper", "endmondo", creates my route? Should I use Accelerometer or/and compass to create a route between CLLocation background points?
Some code:
//location manager init
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
#pragma mark - CLLocationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([self isInBackground]) {
if (self.locationUpdatedInBackground) {
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
self.locationUpdatedInBackground(newLocation);
[self endBackgroundTask];
}
} else {
if (self.locationUpdatedInForeground) {
self.locationUpdatedInForeground(newLocation);
}
}
}
UPD:
Justed tested my app with next properties
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.activityType = CLActivityTypeFitness;
self.locationManager.pausesLocationUpdatesAutomatically=NO;
In this case I have about 10 fired events during 1,5 hour trip
Use
kCLLocationAccuracyBestForNavigation
check this.
You need to add in your "Info.plist" file the key UIBackgroundModes (array) with the value "location" (app registers for location updates).
You can check all background modes here.
So your app uses location services. Then please read the Location Awareness Programming Guide.
You need to make some changes to your Info.plist:
If your app relies on location services to function properly, add location-services to UIRequiredDeviceCapabilities
if your app requires GPS hardware, add gps to UIRequiredDeviceCapabilities
if you need to run your app longer then 10 minutes in the background, add location to UIBackgroundModes. Then your location manager will deliver locations beyond the 10-minute-limit.
you should also set NSLocationUsageDescription (can also be localized)
Getting Location Events in the Background
If your app needs location updates delivered whether the app is in the foreground or background, there are multiple options for doing so. The preferred option is to use the significant location change service to wake your app at appropriate times to handle new events. However, if your app needs to use the standard location service, you can declare your app as needing background location services.
An app should request background location services only if the absence of those services would impair its ability to operate. In addition, any app that requests background location services should use those services to provide a tangible benefit to the user. For example, a turn-by-turn navigation app would be a likely candidate for background location services because of its need to track the user’s position and report when it is time to make the next turn.
Your problem is the background handler. Remove it and enable gps background mode in plist file. then you should get full power gps all the time.
Set property pausesLocationUpdatesAutomatically=NO
This is new in ios6.
From CLLocationManager:
Allowing the location manager to pause updates can improve battery
life on the target device without sacrificing location data. When this
property is set to YES, the location manager pauses updates (and
powers down the appropriate hardware) at times when the location data
is unlikely to change. For example, if the user stops for food while
using a navigation app, the location manager might pause updates for a
period of time. You can help the determination of when to pause
location updates by assigning a value to the activityType property.
The default value of this property is YES.
For analysis add these methods to your LocationManager delegate:
- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager {
NSLog(#"locMan: locationManagerDidPauseLocationUpdates");
}
- (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager {
NSLog(#"locMan: locationManagerDidResumeLocationUpdates");
}
You can set up monitoring location stuff in you VC as below
in viewDidLoad method do as below
CLLocationManager locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;(Accuracy according to your need)
[locationManager startUpdatingLocation];
than you have to overrite below two optional delegate methods of CLLocationManagerDelegate protocol
for iOS6+
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{}
and for iOS 2 to 6
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
in these methods you will get updated location. use it as you want.
every time location updated these method get calls.
you don't ask for code. You ask for: "I'm looking for an open source app or library"
It may help you to visit this website.
hope it helps you,
Also a tutorial.
Here was my solution to this,
Declare the instance variable:
CLLocationManager *locationManager;
Be sure to include the delegate
<CLLocationManagerDelegate>
In viewDidLoad:
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move, location is updated
locationManager.desiredAccuracy = kCLLocationAccuracyBest; // get best current locaton coords
locationManager.headingFilter = 1;
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
Implement the delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
int degrees = newLocation.coordinate.latitude;
double decimal = fabs(newLocation.coordinate.latitude - degrees);
int minutes = decimal * 60;
double seconds = decimal * 3600 - minutes * 60;
NSString *lat = [NSString stringWithFormat:#"%d° %d' %1.4f\"",
degrees, minutes, seconds];
NSLog(#" Current Latitude : %#",lat);
latitudeLocation.text = lat;
degrees = newLocation.coordinate.longitude;
decimal = fabs(newLocation.coordinate.longitude - degrees);
minutes = decimal * 60;
seconds = decimal * 3600 - minutes * 60;
NSString *longt = [NSString stringWithFormat:#"%d° %d' %1.4f\"",
degrees, minutes, seconds];
NSLog(#" Current Longitude : %#",longt);
longitudeLocation.text = longt;
}
Disclaimer: I work for Cintric
We also wanted to be able to accurately track a users location in background (even after the app had been killed). We spent a long time solving the problem, especially focusing on battery drain.
We posted a great blog post on how we solved it. And also are providing a drag and drop SDK solution. It's not open source but you can integrate it for free:
You can download the .framework file, drag it into your project and initialize with one line of code:
[CintricFind initWithApiKey:#"YOUR_API_KEY_HERE" andSecret:#"YOUR_SECRET_HERE"];
You can get an API key for free. There are docs explaining everything here.
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.