didEnterRegion fire when app is terminated? - ios

I've implemented the use of GeoFences in my app. I've created a new CLLocationManager property and initialised it in my app's viewDidLoad method simply like so:
[[self.locationManager alloc] init];
I set the delegate to self, start monitoring for regions using startMonitoringForRegion:
Then, I emulate my location while running it using Xcode and the methods didEnterRegion and didExitRegion. The app works perfect while running, but I haven't got the chance to test it as I don't know how to emulate my location while the app is terminated, see my other question
Therefore, I was hoping to get some answers on these questions:
Can I manage background work just like normal with the didEnterRegion and didExitRegion methods? Like calculating, etc?
If my app is terminated, I enter a region, open my app - are my variables from didEnterRegion initialised and set up then?
Do I need to do anything else to set it up to work when my app is terminated, except for the normal CLLocationManager setup that I've done so far?
Thanks!

Related

Beacon / IOS CLLocationManager get current region

I'm doing a program who is looking for beacon, I implemented CLLocationManager and my apps works except one point.
I'm calling startMonitoringForRegion() in order to get the didEnterRegion/didExitRegion callback. Inside these function I'm doing startRangingBeaconsInRegion()/stopRangingBeaconsInRegion() in order to get precise information when the user is in the beacon area.
My issue is quite simple, if the app is started when the user is already in the beacon range, didEnterRegion is not called.
I'm looking for a function like isInRegion() so that when my app start I could do startMonitoringForRegion() then isInRegion() and startRangingBeaconsInRegion() if the user is already in the region.
My current workaround is to call startRangingBeaconsInRegion() when the app start, then in the didRangeBeacons callback, I'm doing stopRangingBeaconsInRegion() if no beacon is found.
I don't think that it's a very clean way and would like to replace by something better if possible
Thanks,
You can use the locationManager:didDetermineState:forRegion: callback, which tells you if you are either Inside, Outside or Unknown.
You can force yourself to get a callback by calling
locationManager.requestStateForRegion(region)
when your app starts up.
See more here: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/#//apple_ref/occ/intfm/CLLocationManagerDelegate/locationManager:didDetermineState:forRegion:

How to stop using the Location Services within my iOS app?

I have an iOS app that uses the CLLocationManager to monitor regions and to get GPS updates. Most of the time, I want my app to continue tracking the cellphone when it goes in background or even when it gets killed, and it works well (I can still see the small arrow in the status bar after my app gets killed). The problem is that I am not able to stop monitoring the regions and GPS updates after my app has been restarted by the Location Services.
When my app gets restarted by the Location Services, I instanciate the CLLocationManager and then call its methods stopRangingBeaconsInRegion and stopUpdatingLocation before setting its delegate to nil and itself to nil.
Thanks to NSLogger, I can see that my callbacks are no longer called, but the small arrow in the status bar stays there (and my app is the only one that I allowed to use the Location Services from the settings menu).
What did I miss? Is there a way to know what still uses the Location Services in my app?
When you call stopRangingBeaconsInRegion, where are you getting the list of regions? The proper way to do this is like below:
for (CLRegion *monitored in [self.locationManager monitoredRegions]) {
NSLog(#"Stopping monitoring on: %#", monitored.identifier);
[self.monitoringLocationManager stopMonitoringForRegion:monitored];
}
for (CLBeaconRegion *region in [self.locationManager rangedRegions]) {
NSLog(#"Stopping ranging on: %# ", region.identifier);
[self.rangingLocationManager stopRangingBeaconsInRegion:region];
}
I finally found that I missed to remove some of my numerous regions. The easy way to avoid this mistake is to retrieve the list of regions monitored with the property monitoredRegions and call stopRangingBeaconsInRegion for each of them. I also forgot to call stopMonitoringSignificantLocationChanges (I didn't know that my app was using it, since I am modifying the app of a former colleague).
How do you know that it is your app that is using the location services?
The small arrow appears if the iOS itself is using the location services in the background.
if you did call stopRangingBeaconsInRegion and stopUpdatingLocation before setting the delegate to nil and you are not getting any callbacks then your app is not using the location services.

CLLocationManager in ios7 stops working

My CLLocationManager starts when the user first enters the app. I am initializing it like this:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kDistanceFilter;
self.locationManager.headingFilter = kHeadingFilter;
And I am using geofencing.
I have defined in my .plist the required background modes.
If I test the app in the simulator using a gpx file, it works fine. So far, so good.
However, I read in these two links:
Start Location Manager in iOS 7 from background task
Background Location Services not working in iOS 7
That in iOS7, when the location does not change for a couple of minutes then the CLLocation goes to sleep.
My question is that:
I do not call didUpdateLocation at all, I only want the didEnterRegion, or didExitRegion. Theoretically, will it work , even the app is killed or user Location has not changed in the last hour and then decides to move?
There are a few elements in your questions:
1- In order not to rehash what is in a previous answer, I would first look at my answer at this link. It will help you resolve around the core location updates stopping if the user stops moving and how you can modify that behaviour:
iOS7 Core Location not updating
2- If the user kills an app in iOS7 (by flicking it up in the app switcher), the app will not restart and as such neither your location updates nor region monitoring will restart after the phone is restarted. On the other hand, if the app is killed because of memory pressures, iOS will restart the app and relaunch your location updates and region monitoring in the background. Also, if you reboot the phone, region monitoring will restart automatically. You obviously must have the background mode enabled.
3- Now you are talking about regions in your questions so I am assuming you have implemented CLCircularRegion. If not, that should be the first step and then "startMonitoringForRegion". In your case, even if the user has stopped moving for a while and then started moving, the app will be awaken/delegate called when the app enters or exit a region.
4- Make sure to use locationManager: didDetermineState: forRegion: as well. This will allow the app to determine if it is inside or outside of the region at start. This is useful when you think of an app being launched and no region crossing has happened but it is important to know whether the user is inside or outside of the region.
Hope this helps

CLBeaconRegion not calling didEnterRegion from termination

I have been doing some reading about CLBeaconRegion and I have setup some iBeacons successfully and had it trigger location updates, even while the application is in the background.
However, from what I've read and carry over from CLRegion, I understand that it should be possible to hit locationManager:didEnterRegion: after the application is terminated.
I've setup my CLBeaconRegion like this:
beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:SERVICE_UUID]
major:0
minor:0
identifier:BEACON_ID];
[beaconRegion setNotifyOnEntry:YES];
[beaconRegion setNotifyOnExit:YES];
[beaconRegion setNotifyEntryStateOnDisplay:YES];
But I am not able to trigger the CLLocationManager's delegate from termination. I've left the region (confirmed by a notification), travelled further away from the beacon, waited for 30 seconds, then travelled back to the beacon, but it does not trigger the delegate while terminated (works great while in the background and foreground).
Should this work from termination? Am I missing something? Any help would be great.
I believe that when you are in the background or not running, it calls locationManager:didDetermineState:forRegion: instead of locationManager:didEnterRegion:, and then only if you've set notifyEntryStateOnDisplay to TRUE.
This is the expected behavior on iOS 7. However, this behavior has been changed under iOS 7.1. iOS 7.1 reverts delegate calls back to pre-iOS 7 behavior.
I've documented this behavior in a blog post of mine.
http://www.simplymadeapps.com/blog/2014/03/7-1-brings-back-geofence-behavior/
EDIT: The below is no longer true as of 7.1. You can still receive notifications even when the application has closed
The behavior of applications being swiped away in the application switcher now has the effect you're describing under iOS 7.
Users who remove your application from the switcher have made a decision to not allow your app to run in the background. Thus, region monitoring will not re-open your application.
Check out the "What’s New with Multitasking" session from WWDC 2013 for more information.
Yeah,
Same behaviour is being noticed .Sometimes even while calling setNotifyEntryStateOnDisplay, didEnterRegion not called even when in foreground.

How does iOS knows which location manager delegate to call on region monitoring while the app is not running?

I might be confusing how region monitoring works, but this is what i have so far:
I am registering a region to monitor through my location manager, which is implemented on a singleton class, this singleton is also set as the delegate of the location manager so the implemented method is being called.
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
This works totally as expected, if the app is active or suspended the method is being called. It also makes total sense because the class has been already loaded and when the region enter event occurs iOS sends this even to my app which calls the location manager who registered (probably has a reference to it) and in turn it calls whatever delegate was also registered along it (since the class is there ready and loaded).
The issue is, what happens when the app has been killed? Is it first launched into the background? How does iOS know what delegate method to call, and if it has already been loaded?
When your app has been killed and gets started for a location update there can't be a location manager delegate yet and as such there are no notifications delivered to that delegate. The system can't know which of your classes should be used as a location manager delegate or how to instantiate it.
Instead your application:didFinishLaunchingWithOptions: gets called as usual, but the UIApplicationLaunchOptionsLocationKey is set in the options dictionary. That tells your app that you need to instantiate a location manager and set it's delegate. Only after you did this the delegate gets called with the region updates.

Resources