Location services behaving weird - ios

I want to detect location services are enabled or not and based on that I want to enable or disable the button in my app. For that I have written
if([CLLocationManager locationServicesEnabled])
// Enable button
else
// Disbale button
But, I found a strange behaviour with this method. From Settings,
1) If I turns location services OFF, for all apps than above method returns NO.(As expected)
2) If I turns locationServices ON, But OFF for my particualr app, than it returns YES.
Is this the correct behaviour. If yes, than is there any other method to find whether location services are enabled or disbaled at app level. Any thoughts.

As you are using locationServicesEnabled method to find whether the location services are enabled for your app or not, I would like to clear that locationServicesEnabled detect whether the location services are enabled for the device or not. It does not check for particular application.
From the Apple Docs It returns a Boolean value indicating whether location services are enabled on the device
You may use locationManager:didFailWithError: to detect the location services for the particular app
From the Apple documentation
If the user denies your application’s use of the location service, this method reports a kCLErrorDenied error. Upon receiving such an error, you should stop the location service.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([[error domain] isEqualToString: kCLErrorDomain] && [error code] == kCLErrorDenied) {
// Location Services are denied.
}
}

You should check the authorizationStatus property of CLLocationManager to see whether your application is authorised to access location information -
if ([CLLocationManager locationServicesEnabled] && (CLLoctionManager.authorizationStatus == kCLAuthorizationStatusAuthorized)) {
// Enable button
}
else {
// Disable button
}

use this
+(BOOL)checkLocationService {
if (![CLLocationManager locationServicesEnabled])
return NO; //location service disabled
else if(kCLAuthorizationStatusAuthorized!=[CLLocationManager authorizationStatus])
return NO; //app's location service disabled
return YES;
}

Related

Location Services Permission reset upon app upgrade on iOS

Summary:
Is it possible for iOS/App Store to reset an app's Location Service permission on app upgrade?
Detailed:
In our recent app upgrade, we believe quite a few of users that had previously granted our app "Always" Location Services permission as a result of enabling certain features were prompted with a While in Use Location Services prompt on first launch of the new version of our app. Since there is no context around this permission prompt, many of our users likely selected Don't Allow at this time.
AFAIK, it is not possible for our app to reset the user's permission settings via code. Is anyone aware of a certain version of iOS and/or device combination that would lead to this behaviour upon app upgrade?
The only time when our app would prompt users for Location Services permissions is if the authorizationStatus is set to kCLAuthorizationStatusNotDetermined. Otherwise we would start to request for location updates.
Here's a snippet of our app's launch code:
CLLocationManager *lmFollowMe = [[CLLocationManager alloc] init];
[lmFollowMe setDesiredAccuracy:kCLLocationAccuracyKilometer];
[lmFollowMe setDistanceFilter:1000];
[lmFollowMe setDelegate:self];
if ([lmFollowMe respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)]) {
[lmFollowMe setAllowsBackgroundLocationUpdates:NO];
}
[self setFollowMeLocationManager:lmFollowMe];
...
if ([CLLocationManager locationServicesEnabled] == YES) {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied) {
...
} else if (status == kCLAuthorizationStatusRestricted) {
...
} else if (status == kCLAuthorizationStatusNotDetermined) {
if ([self followMeStarted] == NO) {
[self setFollowMeStarted:YES];
[[self followMeLocationManager] requestWhenInUseAuthorization];
}
} else {
[[self followMeLocationManager] startUpdatingLocation];
}
...
Thanks!
You can not change location permission through code, but if user denied location permission then you can show alert for ask location permission with 'Setting' & 'Cancel' buttons.
If user click on 'Setting' then you can redirect user to application's setting page to update location permission by following code.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
Thanks.

IOS Swift User Location Authorization

I have an app that is tracking a User's location. I have much experience with this and have requested when in use Authorization and have added the key to my P-List, however I still receive this error:
"Trying to start MapKit location updates without prompting for
location authorization. Must call -[CLLocationManager
requestWhenInUseAuthorization] or -[CLLocationManager
requestAlwaysAuthorization] first."
The location Manager that I am using is not in the ViewController but in another class.
It doesn't matter where those methods are called from, so you could call either of those methods either from your app delegate's applicationDidFinishLaunching method (these authorization methods run asynchronously) or in the viewDidAppear method of your very first view controller.
check the [CLLocationManager authorizationStatus] before setting mapView.showsUserLocation = YES or startUpdatingLocation
Make sure that your CLLocation variable is strong.
(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) //or kCLAuthorizationStatusAuthorizedAlways
{
self.mapView.showsUserLocation = YES;
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
You must use anyone of the authorization
self.locationManager.requestWhenInUseAuthorization(); or self.locationManager.requestAlwaysAuthorization();
Anyhow the warning will not come for the second time after the user accept the permission

CLLocationManager Disable use of the location by the application

I have a switch for the user to disable / enable the use of the location by the application. I am having two problems.
1 - When the native ios popup appears to ask if he wants to allow the use of location, and he says no, the promixa time I request permission popup is no longer displayed, and the only way to enable the user permission It is in the iPhone settings.
2 - If the user has allowed the use of the location, but then at some point you want to disable the switch is present in the application, it can not.
below is the code I am using.
-(IBAction)avancar:(id)sender{
if (locationManager == nil) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
}
if (switchPermissao.isOn) {
[locationManager startUpdatingLocation];
if(IS_OS_8_OR_LATER) {
[locationManager requestWhenInUseAuthorization];
[locationManager requestAlwaysAuthorization];
}
}else{
[locationManager stopUpdatingLocation];
[self performSegueWithIdentifier:#"tela2" sender:self];
}
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusDenied) {
[switchPermissao setOn:NO animated:YES];
}
else if (status == kCLAuthorizationStatusAuthorizedAlways
|| status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[switchPermissao setOn:YES animated:YES];
}
[self performSegueWithIdentifier:#"tela2" sender:self];
}
RE: 1) The OS will only show the permission dialog once. After the user makes their selection, the OS will not show the permission dialog again even if your code asks for permission again. So, you must handle this with your code to present the user with a custom dialog/alert. To do this, use the CLLocationManager authorizationStatus to get the current status. Only when this status is kCLAuthorizationStatusNotDetermined will the OS show the system permission dialog. In all other cases you need to handle the permission with a custom dialog.
RE: 2) Your app cannot change the status of location services, this can only be changed by the user under the system Setting. To handle this you can present a custom dialog that will open the system Settings for your app so the user can change the status. You can use UIApplicationOpenSettingsURLString, in iOS 8, to open the system Settings for your app.

CLLocationManager suddenly not asking for permission and not showing up in Privacy tab

In my app, I created a class that deals with location services. For example, I start location services like this:
- (void)startLocationServices{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
if([CLLocationManager locationServicesEnabled] == YES && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized)
{
[locationManager startUpdatingLocation];
}
else {
//NSLog(#"Location services is not enabled");
//[self locationDeniedPolicy];
}}
I make my viewcontrollers subclasses of this location class if I ever needed the location of the user.
The location class itself is a subclass of UIViewController.
This used to work fine. When the user navigates to a view controller that is a subclass of this location class, it would ask for location permission for the first time. Also, the app would be listed in the privacy tab of the Settings app.
I suddenly realized that the app is no longer showing up in the Privacy tab and is not also asking for location permission. It does not use the location services at all! I have no idea why this happened? Was it an update to xcode that changed things? No idea!
Any clue?

why self.locationManager stopUpdatingLocation doesn't stop location update

Problem: It seems I can't stop Core Location from sending updates to my app / tracking.
What am I doing: In my viewWillAppear I call self.locationManager and pass it to a method to show user's location on the map (an instance of MKMapView). The getter is overridden to check for availability of the serive, to see whether its authorized. If so, it allocs/inits and startMonitoringSignificantLocationChanges and returns.
In viewDidDisappear, I call [self.locationManager stopUpdatingLocation]. But still I can see the location icon in the status bar. Even when I terminate the app by double tapping the home button and closing it, the icon is still there... even after extended amount of time (10+ minutes). When I go to the Settings App, it tells me that my app is still using location services (purple icon).
Question: What am I missing here? Why location update doesn't stop?
Thanks in advance.
The opposite of startMonitoringSignificantLocationChanges is not stopUpdatingLocation, it is stopMonitoringSignificantLocationChanges.
You probably want to replace startMonitoringSignificantLocationChanges with startUpdatingLocation for the sake of more regular updates, unless you have a specific reason for monitoring only for significant location changes.
Check out the CLLocation documentation for further detail.
I too just experienced the same problem as Canopus. It appears that even if stopUpdatingLocation is called the navigation pointer still resides on the status bar if I have showUserLocation enabled. Perhaps this is a bug? It may be as I am running and testing with iOS 4.2.1 and this issue may have been fixed in a later SDK.
I would think that if stopUserLocation is called it would also stop showing the user location since the view I am using it in has already disappeared and is subsequently deallocated.
It appears that you must set showUserLocation to NO before stopping user location updates.
Anyway, in my viewDidLoad method I have the following code:
self.mapView.showsUserLocation = YES;
More code...
- (void)viewWillDisappear:(BOOL)animated
{
if (locationManager)
{
mapView.showsUserLocation = NO;
[locationManager stopUpdatingLocation];
}
[super viewWillDisappear:animated];
}
- (void)dealloc
{
if (locationManager)
{
[locationManager release];
locationManager = nil;
}
(other code)
}
Swift:
Your map AND location manager both need to be stopped:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
locationManager.stopMonitoringSignificantLocationChanges()
locationManager.stopUpdatingLocation()
mapView.showsUserLocation = false
}
You can debug/check location services usage right there in Xcode, in the debug navigator under Energy Impact.
I solved this setting nil to locationManager property after delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// Your code getting coordinates
//Here set nil
locationManager = nil;
}
My app requests "always" auth. Only a certain feature within the app requires that. If the user turns that feature off then on app close we can stop location updates (with the goal of saving battery and removing the location icon from the status bar). I too thought stopping was not working because after app close the location icon in the status bar was still there even though my app was the only app running on my phone with location access and "on app close" I just told it to stop updating locations.
For me the solution was to be a bit more patient and then I realized that it takes iOS about 10-15 seconds to turn off location hardware and update the status bar. I didn't have to nil out my location manager or anything special, just stopped updates on app close, waited 15 seconds, and observed iOS remove the location icon from the status bar. Hope this helps somebody out there!
I was working with CLLocationManager in Swift and I think is relevant to the either Swift or Objective-C but, I just created a boolean which I update to true whenever I have received the location update. Since in my case I just need it once on launch.. Example,
// my boolean to stop location updates
var alreadyUpdatedLocation = Bool()
Also, in my case I have created a helper function that whenever I get the data/location of the user, I just call my own stopUpdatingLocation like this,
// helper function to stop updates
func stopUpdationgLocation() {
// since I received my data within a block, I don't want to just return whenever it wants to :)
dispatch_async(dispatch_get_main_queue()) {
// the building stop updating location function call
self.locationManager.stopUpdatingLocation()
// my own trick to avoid keep getting updates
self.alreadyUpdatedLocation = true
}
}
Then, where ever you use the location updates that you have received, you could do this...
// avoiding multiple calls after I have received user location
if(self.alreadyUpdatedLocation) {
return
}
I hope it helps!
try this..
if ([CLLocationManager significantLocationChangeMonitoringAvailable])
{
[self.locationManager startMonitoringSignificantLocationChanges];
}
[[self locationManager] stopUpdatingLocation];
If you are using the GoogleMaps SDK for iOS, I found that if you call
locationManager.stopUpdatingLocation()
and still have
mapView.isMyLocationEnabled = true
then the gps icon remains.
What I chose to do is initially show the user's location on the map and then turn it off after 8 seconds. This worked for me using the GoogleMaps SDK. I added this in ViewDidLoad:
DispatchQueue.main.asyncAfter(deadline: .now() + 8.0, execute: {
self.locationManager.stopUpdatingLocation()
self.mapView.isMyLocationEnabled = false
})
You could put the same code in viewWillDisappear if you prefer to not have the gps icon in the status bar when you segue to another view.
Problem:
In my case I use both startMonitoringSignificantLocationChanges and startUpdatingLocation.
Even after stopping the location through locationManager.stopMonitoringSignificantLocationChanges() &
locationManager.stopUpdatingLocation().
My location is getting called continuously.
Solution:
1. Check whether you have invalidated the timers.
2. Initialize locationManager.delegate = nil.
These will surely solve your problem.

Resources