My app features a map and when the user long presses on it, I need the current phone location to appear on the map. As #Chen advised it looks like getCurrentLocation() is the proper method to use in my case. Please note that I don't want to use a LocationListener because I want the user to have control on when they want to update their location.
Moreover I chose this manual location update because #Shai-Almog discouraged location polling. So after reading this post I first set the timeout to 20 s as written below to get the current phone location :
Dialog ip = new InfiniteProgress().showInifiniteBlocking();
Location currentLocation = locationManager.getCurrentLocationSync(
ParametresGeneraux.LOCATION_TIMEOUT_MILLI);
// We try to get something
if (currentLocation == null) {
currentLocation = locationManager.getLastKnownLocation();
}
ip.dispose();
But it was not sufficient and the last known location was "always" provided (I did not count maybe 5 times in a row) although the little location icon appeared in the toolbar. So I set it to 40 s but the actual current location did not come either after this twice as big amount of time (only the last known location which is > 2km away was provided).
However if I start Google Maps on Android (KitKat), the location is instantaneously accurate. And then if I go back to my app and press the map the current location is found. Actually I found a post dealing with a difference in accuracy between Google Maps and Android API but it was pertaining to Shangai / China, not the EU (France).
Consequently my question is twofold :
first how can there be such a huge difference on the same device between Google Maps and Codename One ?
then if I don't set a timeout to getCurrentLocation() how can I interrupt the location searching when the user is fed up waiting ?
Any help appreciated,
BR
Instant location will work if the Google Maps location services is turned on. If you enabled or disabled one of the android.playService build hints you must also enable android.playService.location=true to get the fast location service used by maps.
Related
I have an iOS app that uses Core Location to get the user's location, which pops up the request for permission on the first attempts. However, there are moments where the user will not be able to operate the screen, so at these times I don't want to ask for a location. I check before each call to CLLocationManager startUpdatingLocation, and set map views to not show the user location. The problem is that there is still something trying to access the use location, as the permissions popup is still shown, and I am unable to find where this happens.
So, what other actions could trigger this? And, probably most useful: is there a way I can set a symbolic breakpoint on something that fires always whenever access to the current location is requested? I tried setting one on [UIAlertView show], but that doesn't fire, presumably because the alert is shown by the system, rather than my app?
When the user launches the app for the first time and attempts to login, they are prompted with the iOS dialog - "Turn On Location Services".
I need to capture when the user clicks "cancel". Is there a Notification sent? If so, what is its name? I've been unable to locate it.
The CLAUthorizationStatus is kCLAuthorizationDenied when Location Services are Disabled OR the user clicked "Don't allow". When the user clicks "Cancel", it does not fire the authorizationChange event. When user clicks "Cancel", the app just hangs.
Short answer: You can't catch that notification. You can infer about the user choice and act consequently by using CLLocationManager methods (the longer answer below).
Longer answer:
Firstly, welcome on Stack Overflow. Before kindly posing your question, and trying to be collaborative with people that are here to help, it's a good idea to search if somebody else previously posed the same question.
A brief search gave (just to mention some of them):
How to handle “Cancel” button on Alert pop up for Location services
How to get location services to reprompt the user for location permission if they accidentally refused it?
locationManager:didFailWithError: not called if user Location Services are off
How to prompt user to turn on Location Services…again
How can I prompt the user to turn on location services after user has denied their use
How to ask permission from user for second time to allow to access the current location?
Now, let's try to summarize them all, starting from iOS docs:
If your app relies on location services to function properly, you should include the UIRequiredDeviceCapabilities key in the app’s Info.plist file. You use this key to specify the location services that must be present in order for your app to run. The App Store uses the information in this key from preventing users from downloading apps to devices that do not contain the listed features.
Important: If your app uses location services but is able to operate successfully without them, do not include the corresponding strings in the UIRequiredDeviceCapabilities key.
So, if your app really needs to access the user's position you should add location-services and eventually gps to UIRequiredDeviceCapabilities.
Then, somewhere in your code - when needed, you have to check if the location services are enabled.
[CLLocationManager locationServicesEnabled]
they may be disallowed for three reasons:
The user can disable location services in the Settings app.
The user can deny location services for a specific app.
The device might be in Airplane mode and unable to power up the necessary hardware.
You are interested in the second case: the user refused to allow your app to use the location services.
Again, from the docs:
Important: In addition to hardware not being available, the user has the option of denying an application’s access to location service data. During its initial uses by an application, the Core Location framework prompts the user to confirm that using the location service is acceptable. If the user denies the request, the CLLocationManager object reports an appropriate error to its delegate during future requests. You can also check the application’s explicit authorization status using the authorizationStatus method.
[CLLocationManager authorizationStatus]
That may return:
kCLAuthorizationStatusNotDetermined if the user has not yet made a choice regarding whether this application can use location services.
kCLAuthorizationStatusRestricted this application is not authorized to use location services. The user cannot change this application’s status, possibly due to active restrictions such as parental controls being in place.
kCLAuthorizationStatusDenied The user explicitly denied the use of location services for this application or location services are currently disabled in Settings.
kCLAuthorizationStatusAuthorized This application is authorized to use location services.
If[CLLocationManager locationServicesEnabled] returns NO and you attempt to start location services anyway (i.e. calling [locationManager startUpdatingLocation]), the system prompts the user to confirm whether location services should be re-enabled. Given that location services are very likely to be disabled on purpose, the user might not welcome this prompt.
I suppose you know, and did all the previous steps (I'm only sure you checked the authorizationStatus). You refused to show us the significant code of your app so I can only suppose the overall logic behind. Now you said your app hangs. This should be because you didn't catch the error properly? Catching the error is the way to re-prompt the user, if you wish.
After calling [locationManager startUpdatingLocation], if not authorized, your delegate should define a locationManager:didFailWithError: in order to catch the kCLErrorDenied.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
You may show, at this point, a UIAlert to insist asking the user to give you access to its position, or trigger a change in the UI or whatever you like.
Final notes
I hope you understand why I was asking for the code: the reason was to offer you an alternative solution instead of reply "You can't catch the 'Cancel' notification".
If this answer does not satisfy your question please elaborate why you need to catch the pushing of the "Cancel"/"Do not allow" button, so we can provide alternatives.
Clearly my advice is to not annoy people to death by continuously ask them for enabling location services if they don't want.
Post scriptum: Maybe that the answer looks pedantic and obvious in certain parts if not all to you, but we are here to provide answers also for future readers.
If we try to access the user's location, iOS will tell the user that our application wants to use their location.
If I do this
[locationManager startUpdatingLocation];
An alert will show.
However, that only happens once.
It looks like some variable or default must have been set up once that display pops out.
How do I reset those default so that next time my app wants to use location users will be asked again?
Google map can displays that again and again.
It's Apple that asks them for permission, not you
Translation: You don't have any control over that part of the process. The little popup:
is only shown by Apple when you first ask for it - so the user always feels in control. After they accept for the first time, Apple assumes they are OK with your app getting their location information from their device, and won't show it again*.
*Unless they specifically go into Settings and disable Location Services for you app.
It's only showed on the first time and there's nothing you can do to change that. What you can do is ask your users to allow it on settings.
You can check if your app has permissions by checking:
[CLLocationManager locationServicesEnabled]
From the docs:
The user can enable or disable location services from the Settings application by toggling the Location Services switch in General.
You should check the return value of this method before starting location updates to determine whether the user has location services enabled for the current device. If this method returns NO and you start location updates anyway, the Core Location framework prompts the user to confirm whether location services should be reenabled.
GPS signal is lost when App is resumed from long time suspend mode.
And/or after user goes into a building where GPS is weak and then resumes the App.
The blue dot disappears and the map is centered at lat:0 long:0 ( which is somewhere in
the ocean near Nigeria-Africa )
If you launch another GPS app at that point in time, such as Apple Maps,
you DO see the blue dot, even if not so accurate.
The only way a user can fix it - is by killing my app completely and start it again.
It happens on both iOS 5.x and iOS 6.x.
Before going into details, I would really like to ask:
Does anyone encounter this problem ??
Its very annoying but, I couldn't find anyone complaining about this
anywhere on the web - very weird.
I'm using normal CLLocation with showUserLocation=YES,
Nothing magical, no special accuracy tuning or whatever, just simple default
implementation.
I have already tried restarting every possible component when App is resumed;
showUserLocation=NO;
showUserLocation=YES;
or
[locationManager stopUpdatingLocation];
[locationManager startUpdatingLocation];
or
even releasing locationManager and initialize it again doesn't help!
( also tried restarting it with a delay using dispatch_after )
Is there any programmatic way to force RESET the GPS signal or CLLocation in ios ?
Will appreciate any relevant discussion!
I Think you default Location is set "None" so this type of issue created.
Go to
Edite Scheme..
|
|
"Run YourProjectName" / Left Hand Side
|
|
Select "Option" Tab
|
|
Default Location
|
|
Choose any Location such like , "London England"
When you say that you've tried stopping/starting the CLLocationManager object, are you saying that the call-back you get in your delegate gives you a 0,0 coordinate, or are you trying to access the location directly using the location property in CLLocationManager?
I work on a location based app and one thing I can tell you is that you cannot count of directly getting the location of a CLLocationManager object. The only reliable way to get location information is to rely on the callback of the CLLocationManager class by implementing
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
The way I handle CLLocationManager in my app (now I'm not saying this is optimal or ideal for your use case but it does allow us to provide a solid location-based experience to the user on app launch/resume)
Wrap the CLLocationManager into a location management class (usually using a singleton) - I think this can be a subclass of CLLocationManager but in my case it's just a subclass of NSObject with a CLLocationManager object as a property
Store the last known valid location in this singleton, and then write it to disk (NSUserDefaults or another location - need to re-check if you're allowed to store user location in NSUserDefaults but we've done it in our app and doesn't seem to affect the approval process)
Re-implement a way to get the current location in your custom class - basically check if CLLocationManager is returning 0,0 and if it is, return your cached position instead
Not strictly necessary but if you have multiple views/pages that need to use the location, implementing the observer model works well (since your singleton is now CLLocationManager's delegate, you need to have a way to pass this information on to your view controllers).
With the above, on my map page (or wherever I'm displaying user location) - I basically update the map with the cached location once (in viewDidLoad) and then I allow one update to the map through the delegate-callback. Once that call-back is received, I then set showsUserLocation to YES (if the call-back isn't called, then you don't have a valid location yet and so setting showsUserLocation at that point doesn't do anything).
I hope this helps and feel free to let me know if you have any further questions!
I have an app which uses forge.geolocation.getCurrentPosition. It seems that at times, the location does not refresh. I can open the iOS app in one position, and then an hour later 5 miles away, open the app again (either resume, or completely close the app from the tray, and re-open) and still the old location is returned.
I am using this form
forge.geolocation.getCurrentPosition({enableHighAccuracy: true}, function (location) {})
Note that when opening/resuming the App, the GPS icon at the top DOES show up however the location returned to the javascript code is incorrect.
The above bug was reproduced on iOS 6
After opening the Maps app, and going back to my app, the correct location is finally returned.
Any idea how to fix this?
getCurrentPosition returns the best data it has at that particular time - I'd recommend calling the method a number of times until the indicated accuracy is reduced to an acceptable level.
What we might do in the future is support watchPosition so that something like https://stackoverflow.com/a/8554835 would be possible through the forge API