I was reading your comment below:
"I don't know what you mean by "power save" mode, but if you're thinking of when the screen is locked/off, that does not stop Core Location from running if your app is still running. On the contrary it's easy to run down your phone's battery much more quickly than you'd expect if you lock the phone while an app that uses Core Location is running, because the phone will continue to update the app as new location data is available. You could avoid this in your application by listening for UIApplicationWillResignActiveNotification to detect the screen locking, and UIApplicationDidBecomeActiveNotification to detect unlock."
I have an app that uses core location, and as long as my phone is not locked, I get regular NSlog entries from core location. The moment I lock it though, the NSlogs from core location stop until I wake the phone. My code that does the logging is:
-(void) locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if (startingPoint == nil)
self.startingPoint = newLocation;
userLocation.latitude = newLocation.coordinate.latitude;
userLocation.longitude = newLocation.coordinate.longitude;
NSLog(#"Update from LM: Latitude = %f",newLocation.coordinate.latitude);
NSLog(#" Longitude = %f",newLocation.coordinate.longitude);
}
Am I missing something?
That looks like part of a response that I wrote to a question over a year ago. See my comment there about it.
For future reference, if you're going to write a response to an answer, you shouldn't create a new question. Stack Overflow has a comment feature that's designed for this purpose. Saying "your comment" with no context at all is asking for confusion (I just happened to read Stack Overflow today, or I wouldn't have noticed).
Related
I have an app which uses CLLocationManager to track the user's route, drawing dots along the path taken. The app runs in the background using Required background modes > App registers for location updates.
As I understand, anything that happens in the background needs to be called from locationManager:didUpdateToLocation:fromLocation as this is the method that gets called with each location update.
The problem I'm having is that sometimes this stops getting called. It seems to happen when the user's location does not change much within the space of maybe 15 minutes or so. As far as I can tell, calls to locationManager:didUpdateToLocation:fromLocation just stop, presumably to save the battery. Unfortunately, it doesn't resume again when you're back on the move.
I presume there's no way to override this behaviour, so I would like to use Notification Centre to inform the user that the app is no longer recording the route. The problem is, how can the app know that this has happened? If locationManager:didUpdateToLocation:fromLocation is not called, I can't fire my notification. If it is being called, the notification should not fire.
Is there some kind of system notification that says location updates will cease?
I'm finding it quite hard to debug this as I can't take my Mac everywhere when I'm out and about testing the location on the device (there's only so much you can do in the simulator). Any tips for debugging would also be much appreciated!
If you haven't found the answer, I think it is because of a new attribute added to CLLocationManager called pausesLocationUpdatesAutomatically. The attribute defaults to YES, and its behaviour is exactly as you describe. Try setting it to NO and I think it will fix your problem.
Starting in iOS9, make sure you're also setting this property on your location manager:
[locationManager setAllowsBackgroundLocationUpdates:YES]
There's a delegate for location update did Fail
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
There are a few kinds of errors: kCLErrorDenied kCLErrorNetwork Add code here to handle them in the delegate method above not updating location, perhaps a UIAlertView to tell the user.
Personally, I call [locationManager stopUpdatingLocation]; on any error then restart it with an error message depending on the reason for the failure.
ALSO re background, check code in your appDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
[self saveContext];
if ([CLLocationManager significantLocationChangeMonitoringAvailable]) {
// Stop normal location updates and start significant location change updates for battery efficiency.
[self.locationHandler.locationManager stopUpdatingLocation];
[self.locationHandler.locationManager startMonitoringSignificantLocationChanges];
}
else {
NSLog(#"Significant location change monitoring is not available.");
}
}
LASTLY re: testing. You can simulate some errors in location by changing the location movement in the simulator. For example, going from running to driving will cause an error. Going from running to a single specific custom location will cause an error. They should all appear in the delegate method for locationManager above.
I've managed to solve the problem by adding a local notification that fires with a 90 second delay every time a new location is added to the route. When the next location is added, the previous notification is cancelled and a new one is scheduled. This way, if it stops updating, a notification is received by the user (albeit with a 90 second delay). It's not ideal, and it may not be great for battery life, but it is a solution and it's the best I've got for the time being.
#Ron, I meet the same problem as beev describe, and i had already set pausesLocationUpdatesAutomatically to NO. I think because iOS will kill some apps that didn't be triggered in 10 minutes when it's under background. So add local notification maybe a good choice at the moment.
I'm trying using locationManager to get my location and update it to my webservice.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
//some code here
}
It's normal, but if my app goes to the background or phone screen is locked, updating location may be paused. How do I get the location anyway?
Read the full blog post on it: iPhone Background GPS: accurate to 500m, not enough for foot traffic
Here is a tutorial: iOS Multitasking: Background Location
I recommend you set up a handler such as this example:
TTLocationHandler
Configure the handler for the recency and accuracy required. Set up a listener for the notification "LocationHandlerDidUpdateLocation". Put your code to upload the data in a method called on receipt of that notification.
If you do not require fine grain detail, I would advise you use the battery saving options of significantLocationChange monitoring in background. In that case you will not need to add background mode in info.plist and you will not waste resources unnecessarily. The app will be awakened and your method called only on significant movement of the user. There is configurable options in the handler to require constant monitoring in background and/or foreground, and to set recency and accuracy thresholds.
See the LMPinTracker class for example of how to respond and save your data to web or locally. See the thread Invoke get current coordinates every few seconds without NSTimer for discussion of use.
Add This Key to your Application Plist
Required background modes
Mark it as Array, and on its item0 add this Value
App registers for location updates
The app will now get location data in Background too.
I am trying to get Altitude of my location in my application. But every time I try altitude property of CLLocation object I am getting 0.00 as result.
I googled for my query and I got a similar question here and here. This link is saying that if I access CLLocation with wifi or cell tower it will be null. Even if I try to set desireAccuracy to best than even it don't make sure that app will use GPS. It is also saying that if I am indoor that I won't be able to access GPS.
I many cases it its not sure that app will use GPS only. I want some way for getting Altitude from wifi or cell tower too. For that I googled more and I got Google Earth API but I think this is for Microsoft .net technology only.
Now according to this situation I think for a solution I can create a web service in Microsoft Technology and pass my location there and I can get altitude as response but I don't want to do this.
Can anyone suggest me how to get my location's altitude from ios. Is there any way available or not? If yes than please navigate me in right direction.
Thanks in advance.
Edit1
I used CLLocationManager for updating location and when I get my location I need altitude.
Edit2
According to #fishinear's answer I tried following code:
- (void)viewDidLoad
{
[super viewDidLoad];
manager = [[CLLocationManager alloc] init];
[manager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[manager setDistanceFilter:kCLDistanceFilterNone];
[manager setDelegate:self];
[manager startUpdatingLocation];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([newLocation verticalAccuracy] >= 0) {
NSLog(#"Altitude = %lf",newLocation.altitude);
}
NSLog(#"Vertical Accuracy : %lf",newLocation.verticalAccuracy);
}
verticalAccuracy is always -1. It is not changing even after running the app to last 30 Mins. I am runnin ios 4.3.2 on my 3GS. I am indoor so I think it is not accessing GPS using this code even.
To answer your original question:
GPS will always be used if you set desiredAccuracy to Best or BestForNavigation, and distanceFilter to kCLDistanceFilterNone when configuring the CLLocationManager. You will then also get altitude values in the CLLocation event.
However, it takes a short while before the GPS has "locked in" to enough satelites to be able to report the altitude. During that time it will report CLLocation events without altitude values. Therefore, you should ignore the first couple of events until the verticalAccuracy value is good enough for you. Also, check the timestamp, because sometimes the first CLLocation event is an old one.
See Android - Get Altitude By Longitude and Latitude? there is an Android solution but it is easily adaptable to iOS.
The answer is to use the USGS Elevation Query Web Service
From the top answer there, basically you just send an HTML Web request to:
http://gisdata.usgs.gov/xmlwebservices2/elevation_service.asmx/getElevation?X_Value=" +
String.valueOf(longitude) +
"&Y_Value=" + String.valueOf(latitude)
+ "&Elevation_Units=METERS&Source_Layer=-1&Elevation_Only=true";
Then you can parse out the response text from between the <double>...</double> tags
Edit:
It looks like you might be trying to get elevation outside the United States.
Google Maps API does provide an Elevation service and documentation at https://developers.google.com/maps/documentation/javascript/elevation
I having some problem on the iPhone/iPad compass development.
The trueHeading taken from the CLHeading alway give me the '-1' value, I'm stuck here. Here is my code:
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
self.locationManager.headingFilter = 0.5; //1 degrees
[self.locationManager startUpdatingHeading];
I also found out something, that is when I on the map app or the compass app which has use the location stuff, the trueHeading value suddenly read correct. I wonder what is the cause, any idea? It happen on both iPhone4 and on the iPad.
It also happen whenever I off the Location Services in settings and re-enable it, it will become unable to read the correct trueHeading value, i wonder because the location services cannot be enable by the app I creating?
anyway, thank in advance
---My Solution---
see below.
to avoid the heading keep returning -1.000000, not JUST run startUpdatingHeading but run startUpdatingLocation together, this helps.
Try using this...
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBestForNavigation;
// Start heading updates.
if (locationManager.headingAvailable && locationManager.locationServicesEnabled)
{
locationManager.headingFilter = kCLHeadingFilterNone;
[locationManager startUpdatingHeading];
}
and after doing this CLLocationManager delegate methods calls
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
// Use the true heading if it is valid.
[lblAccuracy setText:[NSString stringWithFormat:#"%.1fmi",newHeading.headingAccuracy]];
}
But this coding works on device not in simulator...
Happy coding..
---My Solution---
What I did was, add in the [self.locationManager startUpdatingLocation] to before or after the [self.locationManager startUpdatingHeading]; (when Location Services is off & re-enable from the Settings). I'm not sure this is a good solution, but this is what I did to make it work, if you have any better solution please share.
I had some trouble with the location manager myself and found out that for me it helped to unplug the iPhone from the computer when testing. Somehow the calibration alert only popped up after unplugging the iPhone.
I had this same problem. I moved startUpdatingHeading into a button action, then moved it back to where the CLLocationManager is allocated -- where it had been working fine -- and it started returning only -1.
I rebooted my iPad and it started working again. Hopefully it stays that way.
Edit: Nope, it didn't stay that way. I had to use startUpdatingLocation too. Won't this wear down the battery though? I set desiredAccuracy to kCLLocationAccuracyThreeKilometers, because I am not using location data anyway.
A TRUE reading requires knowing the magnetic variation for the place where you are using the compass. From the previous discussion, it appears to be that the function that corrects the true direction from magnetic direction needs your location for obtaining the variation value. If you don't like to use the location GPS information in your code, I suggest reading the magnetic reading and correct the value by yourself. You need to obtain the variation for the desired location first then apply the following formula: T=M ± V, where T is the true direction, M is the compass magnetic reading and V is the variation. Use "+" for East and "-" for West. I found the allowing web site provide the variation(magnetic declination) for any needed location: http://www.geomag.nrcan.gc.ca/calc/mdcal-eng.php.
When location services are off, the didUpdateHeading delegate method returns only the magnetic heading. You can use it according to your needs. According to Apple docs..
To begin the delivery of heading-related events, assign a delegate to
the location manager object and call its startUpdatingHeading method.
If location updates are also enabled, the location manager returns
both the true heading and magnetic heading values. If location updates
are not enabled, the location manager returns only the magnetic
heading value.
Working on this problem now. I can get updates from Core Motion when I use SpriteKit. It's about being able to call a function continuously like once a frame (1/60th of a second) or every few frames. Without using SpriteKit, the documentation says to invoke the updates within a closure, which I assume will be on their own thread and up to you to release.
There's an algorithm for converting the magnetometer readings to actual degrees relative to true north. Picture a graph that looks like the time domain function of alternating current and you'll see that interpolating the data is a simple matter of applying Maxwell's equations. Here's an example on honeywell
I have borrowed my friend's first gen iPod touch to test my app on. I upgraded the OS to iOS 3.1.3.
I have been following the big nerd ranch book and am trying to get the location to display in the log, but it's inside a view rather than the app delegate.
The location is reported but for some reason it gives her address, over 300 miles away....
The separate maps app reports that it cannot determine my location
I turned the geolocation services on and off and I can only find my home network listed so I can't make the device forget her network.
Here is the code i am using:
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%#", newLocation);
}
What am I doing wrong?
EDIT: I am connected to my home network 300 miles from hers
also the log result is:
<anumber,anumber>+/- 144.27m (speed -1.00 mps / course -1.00) # 2009-06-28 17:58:08 +0100
It seems to think it is 2009...
thanks everyone
Looks like it's using a cached location, and in the place you are now it can't get a location fix. Try testing it again in a place with lots of WiFi (a city/big suburb). Also, check to see if you can find a location in the maps app.
Well there is nothing wrong, the iPod touch does not have a GPS chip. It uses triangulation of WiFi ESSID to vindt it's location.
It will need a network connection to do this correctly.
There was this one time when the timezone on the WiFi router was set incorrectly and that kind of screwed up location info on iPods.
Check your router settings.
Do you have an iPhone?
Make sure the GPS is on (run maps for a bit, small accuracy circle around the blue dot).
Make sure it can see your WiFi network (join it).
Maybe try this with another iPhone also.
Sync the devices with iTunes, and hope that Apple's location/ESSID database is updated by those iPhones at some time in the near future :)