我一直在研究CoreLocation。最近,我遇到了一个问题,这个问题已经在其他地方有所涵盖,但是这些内容都是用Objective C编写的,并且适用于iOS 8。
我感觉有点傻,但是如何使用Swift,在iOS 9上检查位置服务是否已启用?
在iOS 7(可能也适用于iOS 8?)中,您可以使用locationServicesEnabled()
,但是当编译为iOS 9时似乎无效。
那么,我该如何完成此操作呢?
谢谢!
CLLocationManagerDelegate
添加到你的类继承中,然后你可以进行如下检查: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")
}
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")
}
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")
}
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")
}
在 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是有区别的。
以下是 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
}
}
}
}
Swift 4 中只需使用两行代码即可实现:
import CoreLocation
static func isLocationPermissionGranted() -> Bool
{
guard CLLocationManager.locationServicesEnabled() else { return false }
return [.authorizedAlways, .authorizedWhenInUse].contains(CLLocationManager.authorizationStatus())
}
SWIFT (As of July 24, 2018)
if CLLocationManager.locationServicesEnabled() {
}
对于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)
}
}
当您调用-startLocation时,如果用户拒绝了位置服务,则位置管理器代理将接收到一个带有kCLErrorDenied错误代码的-locationManager:didFailWithError:调用。这适用于所有版本的iOS。
要请求位置服务权限,请使用以下方法:
yourSharedLocationManager.requestWhenInUseAuthorization()
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)
}
}
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
}
这是我的解决方案:
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)
locatoinServicesEnabled
方法,即:manager.locationServicesEnabled()
而不是CLLocationManager.loationServicesEnabled()
问题已解决! - Brendan ChangauthorizationStatus
被设置为notDetermined
时,不仅仅是记录日志,更好的做法是提示用户“允许/不允许”。 - mfaani