检查位置服务是否已启用。

109

我一直在研究CoreLocation。最近,我遇到了一个问题,这个问题已经在其他地方有所涵盖,但是这些内容都是用Objective C编写的,并且适用于iOS 8。

我感觉有点傻,但是如何使用Swift,在iOS 9上检查位置服务是否已启用?

在iOS 7(可能也适用于iOS 8?)中,您可以使用locationServicesEnabled(),但是当编译为iOS 9时似乎无效。

那么,我该如何完成此操作呢?

谢谢!

11个回答

285
CLLocationManagerDelegate添加到你的类继承中,然后你可以进行如下检查:

导入CoreLocation框架。
import CoreLocation

Swift 1.x - 2.x 版本:

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 版本:

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 版本

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

在iOS 14中,您将会收到以下错误信息: authorizationStatus()已在iOS 14.0中废弃

为解决此问题,请使用以下方法:
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")
}

8
好的!谢谢!我的问题是我试图在我的管理器上调用locatoinServicesEnabled方法,即:manager.locationServicesEnabled()而不是CLLocationManager.loationServicesEnabled()问题已解决! - Brendan Chang
2
我明白你的代码只是一个例子,但它有点误导人。我认为当authorizationStatus被设置为notDetermined时,不仅仅是记录日志,更好的做法是提示用户“允许/不允许”。 - mfaani
@Honey,当然你可以按照自己的喜好使用它,正如你所说,这段代码只是为了展示它的使用方法。 - Rashwan L

16

在 Objective-C 中,您应该跟踪用户是否已拒绝或未确定权限,然后请求权限或将用户发送到“设置”应用程序。

-(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];
   }

}

实现alertView Delegate,如果用户已经拒绝,则将用户发送到启用位置服务页面。

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

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

初始化位置管理器

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

请注意,kCLAuthorizationStatusAuthorizedAlways和kCLAuthorizationStatusAuthorizedWhenInUse是有区别的。


感谢提供这个 Objective-C 版本,尽管原问题是关于 Swift 的。额外的提示:如果状态未确定,请调用 requestWhenInUseAuthorization;设置相关的 plist 条目以说明使用情况(可能需要本地化);并且可能需要实现 didChangeAuthorizationStatus 方法。 - Giorgio Barchiesi

12

以下是 Apple 推荐的格式。

  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
      }

以下是一个完整的示例。

这包括一个带有按钮的 AlertView,如果之前被拒绝访问,则可将用户带到设置屏幕。

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

9

Swift 4 中只需使用两行代码即可实现:

import CoreLocation

static func isLocationPermissionGranted() -> Bool
{
    guard CLLocationManager.locationServicesEnabled() else { return false }
    return [.authorizedAlways, .authorizedWhenInUse].contains(CLLocationManager.authorizationStatus())
}

9

SWIFT (As of July 24, 2018)

if CLLocationManager.locationServicesEnabled() {

}

这将告诉你用户是否已经选择了应用程序位置权限请求的设置。

5

对于Swift3.0及以上版本,如果需要经常检查位置服务的可用性,请创建以下类:

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

然后在您的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)
        }
    }

4

当您调用-startLocation时,如果用户拒绝了位置服务,则位置管理器代理将接收到一个带有kCLErrorDenied错误代码的-locationManager:didFailWithError:调用。这适用于所有版本的iOS。


谢谢。不幸的是,当我尝试时,它显示:“使用未解决的标识符'kCLErrorDenied'”。你有什么想法吗? - Brendan Chang

1

要请求位置服务权限,请使用以下方法:

yourSharedLocationManager.requestWhenInUseAuthorization()

如果当前状态未确定,将显示一个警报提示用户允许访问。如果访问被拒绝,您的应用程序将在CLLocationManagerDelegate中收到通知,同样,如果在任何时候权限被拒绝,您也将在此处得到更新。
有两个单独的状态需要检查以确定当前权限:
- 用户是否启用了一般位置服务

CLLocationManager.locationServicesEnabled()

  • 如果用户已经授权你的应用程序拥有正确的权限..

CLLocationManager.authorizationStatus() == .authorizedWhenInUse

你可以添加一个扩展作为一个方便的选项:

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

}

当用户第一次请求方向时,它被访问:

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

这里是委托:

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

    if !CLLocationManager.authorizedToRequestLocation() {
        showAlertNoLocation(locationError: .invalidPermissions)
    }
}

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

1

这是我的解决方案:

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

使用方法如下:

LocationManager.shared.checkLocationService()
LocationManager.shared.didChangeLocationAuthorization
    .sink { [weak self] authorization in
        print("::: Location Permission: \(authorization)")
    }.store(in: &cancelBag)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接