Check if location services are enabled
Asked Answered
P

11

111

I've been doing some research about CoreLocation. Recently, I encountered a problem that has been covered elsewhere, but in Objective C, and for iOS 8.

I feel kinda silly asking this, but how can you check if location services are enabled using swift, on iOS 9?

On iOS 7 (and maybe 8?) you could use locationServicesEnabled(), but that doesn't appear to be working when compiling for iOS 9.

So how would I accomplish this?

Thanks!

Publicly answered 18/1, 2016 at 18:50 Comment(0)
C
286

Add the CLLocationManagerDelegate to your class inheritance and then you can make this check:

Import CoreLocation Framework

import CoreLocation

Swift 1.x - 2.x version:

if CLLocationManager.locationServicesEnabled() {
    switch CLLocationManager.authorizationStatus() {
    case .NotDetermined, .Restricted, .Denied:
        print("No access")
    case .AuthorizedAlways, .AuthorizedWhenInUse:
        print("Access")
    }
} else {
    print("Location services are not enabled")
}

Swift 4.x version:

if CLLocationManager.locationServicesEnabled() {
     switch CLLocationManager.authorizationStatus() {
        case .notDetermined, .restricted, .denied:
            print("No access")
        case .authorizedAlways, .authorizedWhenInUse:
            print("Access")
     }
} else {
    print("Location services are not enabled")
}

Swift 5.1 version

if CLLocationManager.locationServicesEnabled() {
    switch CLLocationManager.authorizationStatus() {
        case .notDetermined, .restricted, .denied:
            print("No access")
        case .authorizedAlways, .authorizedWhenInUse:
            print("Access")
        @unknown default:
            break
    }
} else {
    print("Location services are not enabled")
}

iOS 14.x

In iOS 14 you will get the following error message: authorizationStatus() was deprecated in iOS 14.0

To solve this, use the following:
private let locationManager = CLLocationManager()

if CLLocationManager.locationServicesEnabled() {
    switch locationManager.authorizationStatus {
        case .notDetermined, .restricted, .denied:
            print("No access")
        case .authorizedAlways, .authorizedWhenInUse:
            print("Access")
        @unknown default:
            break
    }
} else {
    print("Location services are not enabled")
}
Consist answered 18/1, 2016 at 19:12 Comment(3)
Yup! Thanks! My problem was that I was trying to call locatoinServicesEnabled on my manager, i.e. manager.locationServicesEnabled() rather than CLLocationManager.loationServicesEnabled() Solved!Publicly
I get it that your code is just an example, but it's slightly misleading... I think it's better when authorizationStatus is set to notDetermined then instead of just logging it would be better to prompt the user 'Allow / Don't Allow"Lobito
@Honey, sure you could of course use it as you prefer and as you said the code is just example to show how it could be used.Consist
K
16

In objective-c

you should track user already denied or not determined then ask for permission or sent user to Setting app.

-(void)askEnableLocationService
{
   BOOL showAlertSetting = false;
   BOOL showInitLocation = false;

   if ([CLLocationManager locationServicesEnabled]) {

      switch ([CLLocationManager authorizationStatus]) {
        case kCLAuthorizationStatusDenied:
            showAlertSetting = true;
            NSLog(@"HH: kCLAuthorizationStatusDenied");
            break;
        case kCLAuthorizationStatusRestricted:
            showAlertSetting = true;
            NSLog(@"HH: kCLAuthorizationStatusRestricted");
            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            showInitLocation = true;
            NSLog(@"HH: kCLAuthorizationStatusAuthorizedAlways");
            break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            showInitLocation = true;
            NSLog(@"HH: kCLAuthorizationStatusAuthorizedWhenInUse");
            break;
        case kCLAuthorizationStatusNotDetermined:
            showInitLocation = true;
            NSLog(@"HH: kCLAuthorizationStatusNotDetermined");
            break;
        default:
            break;
      }
   } else {

      showAlertSetting = true;
      NSLog(@"HH: locationServicesDisabled");
  }

   if (showAlertSetting) {
       UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"Please enable location service for this app in ALLOW LOCATION ACCESS: Always, Go to Setting?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Open Setting", nil];
       alertView.tag = 199;
       [alertView show];
   }
   if (showInitLocation) {
       [self initLocationManager];
   }

}

Implement alertView Delegate then sent user to enable location service if already deny by user.

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{

   if (alertView.tag == 199) {
       if (buttonIndex == 1) {
           [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
       }
       return;
   }
}

Init Location Manager

-(void)initLocationManager{
   self.locationManager = [[CLLocationManager alloc] init];
   if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
       [self.locationManager requestAlwaysAuthorization];
   }
}

Please note kCLAuthorizationStatusAuthorizedAlways and kCLAuthorizationStatusAuthorizedWhenInUse is difference.

Kall answered 21/3, 2017 at 7:40 Comment(1)
Thanks for this objective-c version, although the original question was about swift. Additional hints: call requestWhenInUseAuthorization if status is not determined, set the relevant plist entry for usage description (possibly localized), and possibly implement didChangeAuthorizationStatusCandis
D
12

Here is the format Apple recommends.

  switch CLLocationManager.authorizationStatus() {
      case .notDetermined:
         // Request when-in-use authorization initially
         break
      case .restricted, .denied:
         // Disable location features
         break
      case .authorizedWhenInUse, .authorizedAlways:
         // Enable location features
         break
      }

Here is a complete example.

This includes an AlertView with a button to take the user to the Settings screen if previously denied access.

import CoreLocation
let locationManager = CLLocationManager()

class SettingsTableViewController:CLLocationManagerDelegate{

    func checkUsersLocationServicesAuthorization(){
        /// Check if user has authorized Total Plus to use Location Services
        if CLLocationManager.locationServicesEnabled() {
            switch CLLocationManager.authorizationStatus() {
            case .notDetermined:
                // Request when-in-use authorization initially
                // This is the first and the ONLY time you will be able to ask the user for permission
                self.locationManager.delegate = self
                locationManager.requestWhenInUseAuthorization()
                break

            case .restricted, .denied:
                // Disable location features
                switchAutoTaxDetection.isOn = false
                let alert = UIAlertController(title: "Allow Location Access", message: "MyApp needs access to your location. Turn on Location Services in your device settings.", preferredStyle: UIAlertController.Style.alert)

                // Button to Open Settings
                alert.addAction(UIAlertAction(title: "Settings", style: UIAlertAction.Style.default, handler: { action in
                    guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
                        return
                    }
                    if UIApplication.shared.canOpenURL(settingsUrl) {
                        UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                            print("Settings opened: \(success)") 
                        })
                    }
                }))
                alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
                self.present(alert, animated: true, completion: nil)

                break

            case .authorizedWhenInUse, .authorizedAlways:
                // Enable features that require location services here.
                print("Full Access")
                break
            }
        }
    }
}
Disembarrass answered 26/11, 2018 at 1:13 Comment(0)
B
9

SWIFT (As of July 24, 2018)

if CLLocationManager.locationServicesEnabled() {

}

this will tell you if the user has already selected a setting for the app's location permission request

Brooke answered 28/4, 2017 at 22:32 Comment(0)
S
9

It is just a 2 line function in Swift 4:

import CoreLocation

static func isLocationPermissionGranted() -> Bool
{
    guard CLLocationManager.locationServicesEnabled() else { return false }
    return [.authorizedAlways, .authorizedWhenInUse].contains(CLLocationManager.authorizationStatus())
}
Sappy answered 18/10, 2017 at 18:29 Comment(0)
I
5

For swift3.0 and above , if frequent checks are made for the availability of location services, create a class like below,

    import CoreLocation

    open class Reachability {
        class func isLocationServiceEnabled() -> Bool {
            if CLLocationManager.locationServicesEnabled() {
                switch(CLLocationManager.authorizationStatus()) {
                    case .notDetermined, .restricted, .denied:
                    return false
                    case .authorizedAlways, .authorizedWhenInUse:
                    return true
                    default:
                    print("Something wrong with Location services")
                    return false
                }
            } else {
                    print("Location services are not enabled")
                    return false
              }
            }
         }

and then use it like this in your VC

    if Reachability.isLocationServiceEnabled() == true {
    // Do what you want to do.
    } else {
    //You could show an alert like this.
        let alertController = UIAlertController(title: "Location 
        Services Disabled", message: "Please enable location services 
        for this app.", preferredStyle: .alert)
        let OKAction = UIAlertAction(title: "OK", style: .default, 
        handler: nil)
        alertController.addAction(OKAction)
        OperationQueue.main.addOperation {
            self.present(alertController, animated: true, 
            completion:nil)
        }
    }
Illogical answered 27/6, 2017 at 7:35 Comment(0)
D
4

When you call -startLocation, if location services were denied by the user, the location manager delegate will receive a call to - locationManager:didFailWithError: with the kCLErrorDenied error code. This works both in all versions of iOS.

Dedrick answered 18/1, 2016 at 18:53 Comment(1)
Thanks. Unfortunately, when I tried that, it shows: Use of unresolved identifier 'kCLErrorDenied'. Thoughts?Publicly
S
1

In Swift 3.0

if (CLLocationManager.locationServicesEnabled())
            {
                locationManager.delegate = self
                locationManager.desiredAccuracy = kCLLocationAccuracyBest
                if ((UIDevice.current.systemVersion as NSString).floatValue >= 8)
                {
                    locationManager.requestWhenInUseAuthorization()
                }

                locationManager.startUpdatingLocation()
            }
            else
            {
                #if debug
                    println("Location services are not enabled");
                #endif
            }
Saviour answered 27/11, 2017 at 4:58 Comment(0)
G
1

To ask for permission for location services you use:

yourSharedLocationManager.requestWhenInUseAuthorization()

If the status is currently undetermined an alert will show prompting the user to allow access. If access is denied your app will be notified in the CLLocationManagerDelegate, likewise if permission is denied at any point you will be updated here.

There are two separate statuses you need to check to determine the current permissions.

  • If the user has the general location services enabled or not

CLLocationManager.locationServicesEnabled()

  • If the user has granted the correct permission for your app..

CLLocationManager.authorizationStatus() == .authorizedWhenInUse

You could add an extension is a handy option:

extension CLLocationManager {
static func authorizedToRequestLocation() -> Bool {
    return CLLocationManager.locationServicesEnabled() &&
        (CLLocationManager.authorizationStatus() == .authorizedAlways || CLLocationManager.authorizationStatus() == .authorizedWhenInUse)
}

}

Here it is being accessed when the user has first requested directions:

 private func requestUserLocation() {
    //when status is not determined this method runs to request location access
    locationManager.requestWhenInUseAuthorization()

    if CLLocationManager.authorizedToRequestLocation() {

        //have accuracy set to best for navigation - accuracy is not guaranteed it 'does it's best'
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

        //find out current location, using this one time request location will start the location services and then stop once have the location within the desired accuracy -
        locationManager.requestLocation()
    } else {
        //show alert for no location permission
        showAlertNoLocation(locationError: .invalidPermissions)
    }
}

Here is the delegate:

 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

    if !CLLocationManager.authorizedToRequestLocation() {
        showAlertNoLocation(locationError: .invalidPermissions)
    }
}
Gerrigerrie answered 15/1, 2018 at 12:49 Comment(0)
S
1

Swift 5.2

First, set up User class as a CLLocationManager delegate:

import SwiftUI
import CoreLocation

class User: NSObject, ObservableObject {

   let manager = CLLocationManager()

   override init() {
      super.init()
      manager.delegate = self
      manager.requestWhenInUseAuthorization()
      manager.requestLocation()
      manager.startUpdatingLocation()
   }
}

extension User: CLLocationManagerDelegate {

   func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
      print("Location services authorization request")
   }

   func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
      print("Location updated")
   }

   func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
      print("Failed to find user's location: \(error.localizedDescription)")
   }
 }

Then in a view:

if (user.manager.authorizationStatus == .denied) {
   print("Location authorization denied, displaying sheet.")      
}
Suribachi answered 14/4, 2021 at 0:12 Comment(0)
S
1

Here is my solution:

import CoreLocation
import Combine

class LocationManager: NSObject, CLLocationManagerDelegate {
    static let shared = LocationManager()
    private (set) var didChangeLocationAuthorization: CurrentValueSubject<CLAuthorizationStatus, Never> = .init(.notDetermined)
    
    private let manager = CLLocationManager()
    private let notificationCenter = NotificationCenter.default
    var authorizationStatus: CLAuthorizationStatus = .notDetermined
    
    private override init() { }
    
    func checkLocationService() {
        setupLocationManager()
        checkLocationManagerAuthorization()
    }
    
    private func setupLocationManager() {
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
    }
    
    private func checkLocationManagerAuthorization() {
        authorizationStatus = manager.authorizationStatus
        switch authorizationStatus{
            case .notDetermined:
                print("::: -> Location: notDetermined")
                manager.requestWhenInUseAuthorization()
                
            case .authorizedAlways, .authorizedWhenInUse:
                print("::: -> Location: authorizedWhenInUse")
                manager.startUpdatingLocation()
                
            case .denied, .restricted:
                print("::: -> Location: denied")
            default:
                break
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        checkLocationManagerAuthorization()
        didChangeLocationAuthorization.send(manager.authorizationStatus)
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        manager.stopUpdatingLocation()
    }
}

Use like this:

LocationManager.shared.checkLocationService()
LocationManager.shared.didChangeLocationAuthorization
    .sink { [weak self] authorization in
        print("::: Location Permission: \(authorization)")
    }.store(in: &cancelBag)
Slag answered 3/1, 2023 at 13:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.