I have an app that displays a map of the user's location and tracks the user until the app is moved into the background. At that point, the location manager is told to stop updating the location and, instead, to monitor a region (a 100 meter radius around the last known location). On the iOS simulator, it works as expected and shows the Geofencing indicator (same as the regular location services indicator, but only the outline). On the iPhone, it seems to work as expected, but displays the regular location services icon rather than the outline alone.
Is there any reason this might be happening, this discrepancy between the simulator and the phone? I just want to make sure the phone is really only using Geofencing and no other services (i.e. to ensure minimal battery usage).
Additional information:
I have required background mode set to receive location updates – this is in specific cases (when the user enables it) rather than all the time. I've tried disabling this, however, and the problem persists.
The code I'm using for backgrounding the app:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Only monitor significant changes – unless specified
if(!self.viewController.userSpecifiedToUseLocationServices)
{
// Stop using full location services
[self.viewController.locationManager stopUpdatingLocation];
// Create a boundary -- a circle around the current location
self.viewController.currentBoundary = [[CLRegion alloc] initCircularRegionWithCenter:self.viewController.locationManager.location.coordinate radius:kSignificantLocationChange identifier:#"Current Location Boundary"];
// Monitor the boundary
[self.viewController.locationManager startMonitoringForRegion:self.viewController.currentBoundary desiredAccuracy:kCLLocationAccuracyBest];
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Stop monitoring the region
if(self.viewController.currentBoundary != nil)
{
[self.viewController.locationManager stopMonitoringForRegion:self.viewController.currentBoundary];
self.viewController.currentBoundary = nil;
}
// Start full location services again
[self.viewController.locationManager startUpdatingLocation];
}
Well, first of all, Location Services on the simulators have never been a high-fidelity representation of the real devices. So, I wouldn't necessarily assume you'll see the same thing on both test platforms.
Secondly, according to this answer on stack overflow, it sounds like that's the normal behavior on iOS 5 (showing different indicators).
I'd also caution that geofencing isn't a magic technology. The device still has to use location services, and that will drain the battery. I would certainly recommend using Apple's startMonitoringForRegion: or startMonitoringForRegion:desiredAccuracy: and take advantage of their implementation, rather than coding your own. But, I also wouldn't expect battery drain to be negligible.
Finally, you're specifying the accuracy as kCLLocationAccuracyBest, rather than using startMonitoringForRegion:, or specifying a lower accuracy requirement. I don't see how this would not affect battery performance. Greater accuracy means the OS is going to have to either get a higher quality fix, or poll more regularly, or both.
Sadly, there are no free lunches :(
Related
I want to know that locationManager:didUpdateLocations: will call when my phone is in stable position?
In my case its not calling when i put my phone on one place.
I Placed my phone from one location to other location within my room but still its not calling.
Can anyone tell me that when it will call.
When i change location using xcode then its always calling.
I used
self.locMgr.desiredAccuracy=kCLLocationAccuracyBest;
Okay, so you say within the simulator it works, but it does not work when you run your program on the actual iPhone device, right?
You were correct in setting the accuracy. This should work actually unless you have switched off the location update in general for your iPhone (settings under Privacy->Location Services).
If this is all working you maybe want to paste more of your code, but again, I think if it works under the simulator it should work on the device.
The location manager calls for location updates on the accuracy you set. It will not get called on a stable location more than once. you can use distance filter to call it after a certain distance.
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10; //meters
For updating it on the same location you will have to use a timer which will call for updating after every desired interval.
Probably it depends on the accuracy you set to the locationManager.
1).. Cell Radio 2).. WiFi Map, 3).. GPS
If you set best as accuracy the location manager will continue to
check you position, if the location with better accuracy is out of the
range of the distance filter the delegate method will be called again.
GPS is not exact.some time if you move about a feet and still it will
not update. or some time you didn't moved at all and it will update.
Stop testing GPS and Location Services inside! Go outside and move around to test it.
Make sure that you set the delegate for the Location Manager & also
make sure you get the permission for using "User's Current Location."
I am using GeoFencing to set a region and perform some task when user Enters or Leaves the region. Bt it is not working for me, i am using gollowing code
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(some values,some values);
CLRegion *region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:15.0 identifier:#"SF"];
[locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest];
But None of the delegates didEnterRegion and didExitRegion being called when i close the application and the app is monitoring and i move away from that region or enter.
You define a radius of 15m. That is too small. First, try with 50m or more. Look at the map app, if you really have entered that region.
Furthermore, I hope you meant "send to background", instead of closing.
make sure you have set your app to be allowed to run in background? (via plist)
Update:
Finally it turned out that you terminated the application. Then of course you will not get any loctaion events anymore.
Solution:
Don't terminate it via double click on home button follwed by selecting the white cross, simply close it with one click on home button, then it has chance to run in background.
Update2:
Even when the app was terminated, ios relaunches it when it has registered to the location monitoring service:
from CllLocationManager Class Reference
If you start this service and your application is subsequently
terminated, the system automatically relaunches the application into
the background if a new event arrive...
Add CLLocationManagerDelegate in header file.
make sure u added
locationManager.delegate = self;
try increasing the radius and check.
First of all increase the radius you are giving for that particular location and check again if it does not work then by following some easy steps provided in this tutorial you can easily implement Geo-Fencing in your app.
Reference: Apple Documentation
You define a radius of 15m. That is too small. First, try with 50m or more. Look at the map app, if you really have entered that region.
Furthermore, I hope you meant "send to background", instead of closing.
make sure you have set your app to be allowed to run in background? (via plist)
We are developing an app that has heavy GPS usage, and we are unable to optimize the battery life.
Even when the device is not moved, there is significant battery drainage that, according to the code, should not happen.
Here is the code:
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = 100;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
Ideally we want to trigger GPS every 20 minutes (if there is no location change then save battery) OR every 5 minutes if there is location change. According to my developer this cannot be done
Previously we were using kCLLocationAccuracyBest, which was consuming battery very fast and now we are using kCLLocationAccuracyHundredMeters.
startUpdatingLocation - is to get the GPS coordinates. There is another call startMonitoringSignificantLocationChanges which is to get AGPS coordinates which I believe returns the coordinates whenever cell tower will change, and hence consumes battery really fast.
distanceFilter - The minimum distance (measured in meters) a device must move laterally before an update event is generated. On the basis of distance filter we get the GPS fix from the device and then we send the updated GPS coordinates to the server.
Any help will be greatly appreciated
Thank you!
There is another call startMonitoringSignificantLocationChanges which
is to get AGPS coordinates which I believe returns the coordinates
whenever cell tower will change, and hence consumes battery really
fast.
That's exactly what it does, but you're jumping to conclusions about the power required for that. The GPS receiver and WiFi transceiver can be used to help determine location, but they're extra devices that have to be powered to be useful. But mobile phones like the iPhone need to keep in touch with the nearest cell tower anyway in order to receive phone calls, so using cell towers as a source of location information should be very efficient with respect to power. Here's what the CLLocationManager reference page says about -startMonitoringSignificantLocationChanges:
This interface delivers new events only when it detects changes to the
device’s associated cell towers, resulting in less frequent updates
and significantly lower power usage.
It also describes the service as providing "tremendous power savings," so it seems the right tool for the job you describe. Of course, if you're also using the standard location updating mechanism at the same time you won't see that power savings, so make sure you're not using both.
Ideally we want to trigger GPS every 20 minutes (if there is no
location change then save battery) OR every 5 minutes if there is
location change. According to my developer this cannot be done
It sounds like there's some sort of misunderstanding here. You can certainly fire up the GPS every 20 minutes to get a fix if that's what you want, although you can't do that from the background. The significant location change service will notify your app even if it's running in the background, so perhaps your developer is talking about background updates.
Your belief that startMonitoringSignificantLocationChanges consumes the battery really fast is likely incorrect. Cell tower changes usually occur far less frequently than movements of 100 meters. And an iPhone checks for this event even when idle and all apps are sleeping.
However, keeping a cell phone on (e.g. Airplane mode off) when far from any tower (barely 1 bar) will drain the battery of the device whether or not an app is doing any location monitoring.
On stock iOS devices, an app cannot trigger location monitoring purely on a timer basis such every 20 minutes or every 5 minutes, without keeping the device on and your app running in the foreground, which will drain the battery.
If you require a good level of precision, you should startUpdatingLocation and as soon you get the first fix you should then stopUpdatingLocation and then startMonitoringSignificantLocationChanges.
This is enough for most app purposes.
Ideally we want to trigger GPS every 20 minutes (if there is no
location change then save battery) OR every 5 minutes if there is
location change. According to my developer this cannot be done
This could be done using an NSTimer that calls a startLocating (a custom method that creates the CLLocationManager and calls startLocating on it) method every 20 minutes. Make sure you call CLLocationManager's stopLocating once you've found a CLLocation with an accuracy of your liking.
However, doing so mean that for 20 minutes you might be using a location that is totally off. It depends on how you plan to use the location and how precise it needs to be, but maybe what your dev means by "not possible" is that your app needs the user's actual location at all times.
My app runs significant location change updates in the background. However the GPS display icon never turns off..even when app is in the background. Is there a way to use location manager with Significant location change in the background and have the GPS icon NOT display continuously? My users don't understand that it is only periodically obtaining location coordinates and instead think its constantly running in background and thus deleting app thinking its too power intensive. Please help.
I believe that any use of CoreLocation will prompt the location arrow. That includes any of the geofencing CLRegion use, -startMonitoringForSignificantLocationChanges, and -startMonitoringForLocation. I think that is Apple's safeguard that something is using your GPS, even in limited use.
That arrow will be visible till you unregister your application from significant change. But I faced problem, what I can't fine point where I can do this. In my case will be best to unregister on application kill, but with multitasking there is no such ability to handle this moment to unregister.
I implemented background location tracking using standard location services, and it works fine. However, since this implementation uses a lot of power, I decided to switch to significant location changes monitoring. Basically, I just changed all the calls to startUpdatingLocation to startMonitoringSignificantLocationChanges and reused the CLLocationManagerDelegate methods I have implemented before.
The problem is that after switching to significant location changes monitoring, the delegate method locationManager:didUpdateToLocation:fromLocation only gets called once when I start monitoring, and is never called again afterwards. I have moved around the phone for a couple of kilometers, and tried riding a train with it, but still the method never gets called. Am I missing something here? Are there settings I need to enable or special code I need to write in order for this to work?
Thanks!
The significant location change requires cell phone towers in order to operate. If you don't have cell phone reception you will not get any results. You can also call CLLocationManager's significantLocationChangeMonitoringAvailable method to see if it is available.