monitoredRegions empty even though startMonitoringForRegion:desiredAccuracy: is called - iphone

I am developing a iPhone app running on iOS5, and am unable to set up geofences when I call the startMonitoringForRegion:desiredAccuracy: method on click of a button.
It works fine in the simulator when I print out the regions in monitoredRegions, but when running on an actual iPhone 4, the monitoredRegions is always empty. Expectedly, the didEnterRegion: and didExitRegion: methods are not called as well.
Another puzzling fact is that on BOTH the simulator and the iPhone 4 device, the CLLocationManagerDelegate method didStartMonitoringForRegion: is never called as well.
Would appreciate some help here, thank you!
EDIT:
this is method that I call on click of a button:
-(void) queueGeofence: (CLLocationCoordinate2D)selectedBranch userCoordinate:(CLLocationCoordinate2D)userCoordinate radius: (CLLocationDegrees)radius {
geofence = [[CLRegion alloc] initCircularRegionWithCenter:selectedBranch radius:radius identifier:#"geofence"];
CLLocationAccuracy acc = kCLLocationAccuracyNearestTenMeters;
[locationManager startMonitoringForRegion:geofence desiredAccuracy:acc];
[CLLocationManager regionMonitoringEnabled];
NSLog([CLLocationManager regionMonitoringEnabled] ? #"regionMonitoringEnabled:Yes" : #"regionMonitoringEnabled:No");
NSLog([CLLocationManager regionMonitoringAvailable] ? #"regionMonitoringAvailable:Yes" : #"regionMonitoringAvailable:No");
NSLog(#"LOCATIONMANAGER monitored regions: %#", [locationManager monitoredRegions]});
}
Region monitoring is both enabled and available, but monitoredRegions is still giving me back nothing.

If you look in CLLocationManager.h, the comments in the header for startMonitoringForRegion:desiredAccuracy: state that
If a region with the same identifier is already being monitored for this application, it
will be removed from monitoring. This is done asynchronously and may not be immediately reflected in monitoredRegions.
Therefore, you shouldn't necessarily expect that [locationManager monitoredRegions] would include your newly added region since it is added asynchronously.
Are you implementing the delegate method for locationManager:monitoringDidFailForRegion:withError:? Maybe that's getting called instead of locationManager:didStartMonitoringForRegion:. Also note that a region with the same identifier as an existing region will get removed, so you might be running into some unexpected problems because you're reusing "geofence" as your identifier.

First of all, you should be sure, that your app has a permission to use LocationManager. Check it when you alloc your manager.
[CLLocationManager authorizationStatus];
I had the same trouble when start app and decline a permission. And after deleting and rebuilding app. I had a flag, that user didn't accept it. Turn it on.

If you are just going by your NSLog, it probably isn't going to work. [locationManager monitoredRegions] returns an NSSet of CLRegions. They won't display to your log that way. Try this:
NSSet *setOfRegions = [locationManager monitoredRegions];
for (CLRegion *region in setOfRegions) {
NSLog (#"region info: %#", region);
}

Related

startMonitoringSignificantLocationChanges but after some time didUpdateLocations is not called anymore

I have a very strange behaviour. I'm writing an application that uses both fetch and location background mode (don't know it it's important for the problem). I correctly set up the CLLocationManager with a delegate and I start monitoring significant location changes (startMonitoringSignificantLocationChanges) in the AppDelegate.
Immediately I get called didUpdateLocations that gives me some locations. After that no more events are fired even I simulate a different location in Xcode (also using a GPX file) and even I stop and restart the monitoring. I'm not receiving any location both in background and foreground.
The strange thing is that if I start updating locations (using the GPS) it works correctly (doing the same tests... starting and stopping exactly like with startMonitoringSignificantLocationChanges). Obviously I've both didUpdateLocations and didFailWithError (I receive no errors).
This is my initialisation (called by the initialisation of an object in my AppDelegate didFinishLaunchWithOptions):
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
I know that distanceFilter and accuracy are not important for significant location changes and I've already set pausesLocationUpdatesAutomatically to NO.
Am I missing something? And also does exist a way to read if a location fired is coming from wifi, cellular or gps?
Thanks in advance.
You can simulate location for significant change on simulator only with "freeway drive" option from simulator location menu. It will be triggered with some minutes interval.
Allocate the manager on the main thread and check if the manager or the app has always permissions could do the trick.
Apple's documentation note is:
Note: Significant-change location updates require an authorization
status of kCLAuthorizationStatusAuthorizedAlways.
You can check the status using:
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
And maybe
if (status != kCLAuthorizationStatusAuthorizedAlways)
You can request permissions again.

iPhone, call another phone number in response to the first not answering?

I am attempting to create an application that will initiate a call to a priority 1 contact on a call-center-like list.
Then, if that contact does not answer (let's forget the whole problem of answering machines here), I'd like to call the priority 2 contact, and so on, until one of them answers or I exhaust my list.
Is this possible?
I've tried the following:
Hook into the CTCallCenter.CallEventHandler event, and checking the call state for CTCallStateConnected and CTCallStateDisconnected, and I get it to respond to the fact that the call disconnected, without ever connecting, and then attempt to initiate another call like I did the first, but this second attempt just sits dead in the water.
Override the DidEnterBackground method, and periodically check the CTCall.CallState property, basically again trying to respond to a disconnect that was never connected, but this does not appear to work either
I also tried adding a short delay (1 second, 2.5 seconds and 10 seconds) after detecting the disconnected state before attempting the next dial, to allow for the phone application to "settle down" after aborting the call, this did not change anything.
I'm of the opinion that this is better solved at the destination of the phone call. I would either have the phone company configure a "follow me" service, use Twilio or some other 3rd party service (as already suggested), or configure my own PBX using something like Asterisk (Asterisk includes the ability to configure "follow me" type behavior). It provides you much more flexibility and control, even if you did find a way to do this natively in iOS.
Having said that, I did get this to work in iOS assuming the following:
Your app initiates the call.
The phone app is opened, dials the number, and disconnects.
The user explicitly returns to your app. If you managed to get the events while your app was backgrounded, I want to know more :-).
On return of control to your app, the phone events are sent and a new call is initiated.
I have the following snippet of code in my UIApplicationDelegate didFinishLaunchingWithOptions method:
// In appdelegate header, ct is declared as #property (strong, nonatomic) CTCallCenter *ct;
self.ct = [[CTCallCenter alloc] init];
self.ct.callEventHandler = ^(CTCall *call) {
if (call.callState == CTCallStateConnected) {
// do some state management to track the call
} else if (call.callState == CTCallStateDisconnected) {
// check that this is the expected call and setup the
// new phone number
NSURL *telURL = [NSURL URLWithString:myNewNumberURL];
[application openURL:telURL];
}
};
This will make the new call. I'm using the iOS 5 SDK; tested on an iPhone 4s.
EDIT:
Using Return to app behavior after phone call different in native code than UIWebView as a starting point, I've managed to get this to work. Note that I have punted on memory management for clarity. Assuming you use the web view technique for getting back to your app after the call is complete, try something like this in the call completed block:
else if (call.callState == CTCallStateDisconnected) {
// check that this is the expected call and setup the
// new phone number
NSURL *telURL = [NSURL URLWithString:myNewNumberURL];
dispatch_async(dispatch_get_main_queue(), ^{
UIWebView *callWebview = [[UIWebView alloc] init] ;
[self.window.rootViewController.view addSubview:callWebview];
[callWebview loadRequest:[NSURLRequest requestWithURL:telURL]];
// and now callWebView sits around until the app is killed....so don't follow this to the letter.
});
}
However, this may not quite give you what you want either. The user will get an alert on each call request, providing an opportunity to cancel the call.
You could use http://labs.twilio.com/twimlets/findme. You could have the app call a Twilio number and it could use findme to call all the numbers in order.
I didn't take a deeper look at it, but the Deutsche Telekom SDK might contain what you're looking after:
http://www.developergarden.com/fileadmin/microsites/ApiProject/Dokumente/Dokumentation/ObjectiveC-SDK-2.0/en/interface_voice_call_service.html
I really am not sure though (don't have time to really look at it at the moment) - I just remembered I'd read somewhere that they have an iOS SDK that is supposed to also handle call management, so I'm posting the link here for you to find out (and hopefully tell us if it works).
#pragma mark -
#pragma mark Call Handler Notification
-(void)notificationCallHandler {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callReceived:) name:CTCallStateIncoming object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callEnded:) name:CTCallStateDisconnected object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callConnected:) name:CTCallStateConnected object:nil];
}
-(void)callEnded:(NSNotification*)notification {
NSLog(#"callEnded");
}
-(void)callReceived:(NSNotification*)notification {
NSLog(#"callReceived");
}
-(void)callConnected:(NSNotification*)notification {
NSLog(#"callConnected");
}
May this will help you
if you wanna setup a new call, while app is in background, i dont see any proper way for this, a lil hack could be, getting location update (because u can get location updates while app is in background), and location service automatically wakes up your application when new location data arrives, and small amount of time is given to application in which u can execute some code, in that time you may start a new call.
u can read further here:
search this ''Starting the Significant-Change Location Service'' in this link Location Aware programming guide
, and read the paragraph that is written after the code block.

Location services don't stop when application is terminated

I'm currently developing an iPhone application which needs location services for various use including AR.
I test everything on simulator and on my iPhone 3GS and everything went well.
I recently tested on iPhone4 and on iPad2 and the location service (the little icon in status bar) keeps displaying even when I manually kill the app!
The only way to disable this icon is to manually stop the location service for my app in the settings.
Does anyone know something about this?
If needed I can post my code.
Thank you in advance
Edit :
When I kill the application, go to location services, switch off my app the location icon disappears. But when I switch it back on, it reappears! Is that normal?
I've found the answer! It came from region monitoring, which I enabled before, but removed all code using it weeks ago.
As I had already tested on the iPad, and even if I deleted and re-installed the app, the system seems to have kept information on region I monitored.
Thus, as described by the documentation, the iOS kept on locating for my App, just as startMonitoringSignificantLocationChanges.
Thanks for you answers, it gave me a better understanding of the location system and how to efficiently use it (in particular thanks to progrmr and Bill Brasky)
Sounds like you're app is going into the background and still using CLLocation. You can stop CLLOcationManager when you receive notification that you're app is resigning active, that's the best way. Then resume when it becomes active. The answer in this question show how to do that here
[EDIT] When your app goes into the background or resigns active for any reason (ie: phone call) you should stop location services at that time. You need to subscribe to the notifications and provide a method to stop and start location services, something like this:
-(void)appDidBecomeActiveNotif:(NSNotification*)notif
{
[locationManager startUpdatingLocation];
}
-(void)appWillResignActiveNotif:(NSNotification*)notif
{
[locationManager stopUpdatingLocation];
}
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidBecomeActiveNotif:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillResignActiveNotif:) name:UIApplicationWillResignActiveNotification object:nil];
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
I ran into this same exact issue when using the region monitoring tools. It didn't matter what I did to disable the regions, the arrow remained. I did finally solve the issue by cleaning up the calls to locationManager. If you are closing your view and don't need the location manager, set it to nil and/or release it. If you are monitoring location in the background, it will stay up there, but if not, make sure you are cleaning up all your location monitoring.
It seems like it is a bug, but as I found out, it is not. Just requires a bit more cleanup.
I have been battling with this problem for a while, and I think I've finally gotten to the bottom of it..
The reason that the location service doesn't stop when you ask it to is not because you haven't stopped it or released it properly. It's actually caused by releasing and re-allocating the CLLocationManager itself, in my experience.
If you have code which releases your CLLocationManager in applicationDidEnterBackground, and then you allocate a brand new one in applicationDidEnterForeground, etc., then you'll probably have this problem.
The solution is this:
Only create your CLLocationManager object once, in applicationDidFinishLaunching.
To start, call startUpdatingLocation, startMonitoringSignificantLocationChanges etc. as normal.
To stop updates, call the appropriate stopUpdatingLocation, stopMonitoringSignificantLocationChanges etc. as normal.
Never, ever release your CLLocationManager or set its' reference to nil (except possibly in applicationWillTerminate, but that probably won't make any difference).
This way, I went from having my app continue to use location services for up to 12 hours after putting my app away in the background, to the location services arrow disappearing within 10 seconds of backgrounding with this new approach.
Note: Tested on iPhone 4S running iOS 5.1.1. To get accurate results on your app's performance in this regard, make sure you go into Settings->Location Services->System Services and turn off the Status Bar Icon switch. That way, the status bar arrow will accurately reflect usage by apps alone.
Presumably this is so users don't need to stare at the bar to notice some mischievous app is using location services. That icon appears when you use any location services and remains for some indeterminate time afterwards.
This is intentional behavior Apple wants users to know which apps are using their locations. It seems this is sensitive data, wouldn't you agree?
This is the solution which fixed this problem for me.
Just stop monitering location changes in
- (void) applicationDidEnterBackground: (UIApplication *)application
{
[locationManager stopMonitoringSignificantLocationChanges];
locationManager.delegate = nil;
}
not in applicationWillEnterForeground: .Still,it takes a few seconds to disappear locating icon.
I don't know why it isn't working in the latter method.
I've run into that problem a while ago and found it useful to apply only one method of applicationDelegate object
- (void)applicationWillEnterForeground:(UIApplication *)application;
If you'll stop your CLLocationManager from receiving updates inside that call, you'll be alright. Of course you'll need to start updating somewhere else, and - (void)applicationDidBecomeActive:(UIApplication *)application; will be a good choice. Also you need to note, that there are two methods of location awareness
the gps based -(void)start/stop_UpdatingLocation;
and the 3g/wi-fi based -(void)start/stop_MonitoringSignificantLocationChanges;

iPhone locationManager:didFailWithError problem when GPS disabled

So, I've followed other related threads, but for some reason I'm still having this error and I'm about ready to tear my hair out. I have implemented locationManager:didFailWithError to check and see if a user selects 'Don't Allow' to use the current location.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"IN ERROR");
if ([error code] == kCLErrorDenied){
[manager stopUpdatingLocation];
}
}
However, the following error always appears when the user selects 'Don't Allow'...it's strange, especially the order that the text 'IN ERROR' appears.
ERROR,Time,293420691.000,Function,"void
CLClientHandleDaemonDataRegistration(__CLClient*,
const
CLDaemonCommToClientRegistration*,
const __CFDictionary*)",server did not
accept client registration 1
2010-04-19 21:44:51.000
testApp[1414:207] IN ERROR
So, it's outputting this error even before it has a chance to get into the didFailWithError function. Does anyone have any ideas of what might be happening? The rest of the locationManager code is as follows:
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
locationManager.distanceFilter = 2;
[locationManager startUpdatingLocation];
Looks like just an informational message from Core Location. It's not crashing your app, the user will not see it and it does still call didFailWithError with the correct error code.
In my tests, the message appears on the iPhone simulator and device (3.1.3) and the iPad simulator but not the iPad device (3.2).
If you're using MapKit as well, this is an error in MapKit. MapKit is registering with Core Location, and then not properly handling the error reported when the user rejects the location update or it fails. It should pass this error on via a delegate method (as it does for geocoding errors), but doesn't.
Unfortunately I can't think of any way to intercept the message from core location, as MapKit maintains an instance of CLLocationManager which it uses to get the location, and that's the one which is reporting the error to its delegate.

Application crashes when asking if user wants to use Location Services

I have an iPhone app that is using CoreLocation.
Upon first installing the app, the iPhone system message is displayed asking whether or not the user wants to allow location services, if they click yes, my app suddenly displays the first screen of my app (I'm using a navigation controller), and crashes. This is what I see in the log -
warning: UUID mismatch detected with the loaded library - on disk is:
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/PrivateFrameworks/CoreTelephony.framework/CoreTelephony
=uuid-mismatch-with-loaded-file,file="/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/PrivateFrameworks/CoreTelephony.framework/CoreTelephony"
Program received signal: “EXC_BAD_ACCESS”.
And the stack trace looks like this
My code isn't too far off from the LocateMe sample (which works on my device). I have this:
CLLocationManager *clLocationManager = [[CLLocationManager alloc] init];
clLocationManager.delegate = self;
if (clLocationManager.locationServicesEnabled) {
[clLocationManager startUpdatingLocation];
} else {
self.searchBar.placeholder = #"Enter location";
}
Any idea on waht I'm doing wrong?
does your navigation controller support CLLocationManagerDelegate? it looks like it's crashing trying to send you an event.
what does your locationManager:didUpdateToLocation:fromLocation: function look like?
It looks like this is a byproduct of this question
To solve the problem, I wound up following this approach
Basically, in my ViewController's dealloc method -
- (void)dealloc {
locationManager.delegate = nil;
[locationManager release];
}