检查是否启用了位置服务

我一直在研究核心定位系统。最近,我遇到了一个问题,这个问题已经在其他地方讨论过了,但是在 Objective C 和 iOS 8中。

我觉得问这个问题有点傻,但是你怎样才能检查在 iOS9上是否使用迅捷来启用定位服务呢?

在 iOS7(也许是8?)你可以使用 locationServicesEnabled(),但是在为 iOS9编译的时候似乎不起作用。

那我该怎么做呢?

谢谢!

104216 次浏览

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.

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")
}

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.

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

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)
}
}

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())
}

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
}

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)
}
}

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
}
}
}
}

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.")
}