CLLocationManager AuthorizationStatus回调?

时间:2015-01-14 23:37:55

标签: ios swift

在我的应用程序中,我有一个名为" Discover"的标签。 “发现”标签将使用用户的当前位置来查找" stuff"靠近他们。我没有向用户提供通用的授权请求(通常会根据研究得到拒绝),而是向用户提供一个解释我们要求的模式。如果他们说是,则会弹出实际的授权消息。

但是,用户仍然可以选择不提示。有没有办法在提示中添加回调,以便用户选择一个选项后我可以看到他们是否接受或拒绝了?

我试过这个:

func promptForLocationDataAccess() {
    locationManager.requestWhenInUseAuthorization()
    println("test")
}

正如所料," println"在请求提示出现的同时执行,所以我无法这样做。

问题在于,如果用户选择不使用位置数据,则所提供的内容将与他们接受的内容不同。

理想情况下,我希望能够进行某种回调,但此时我会采取任何合理的方向!

6 个答案:

答案 0 :(得分:47)

你可以使用 locationManager:didChangeAuthorizationStatus: CLLocationManagerDelegate方法作为各种“回调”。

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    if (status == kCLAuthorizationStatusDenied) {
        // The user denied authorization
    }
    else if (status == kCLAuthorizationStatusAuthorized) {
        // The user accepted authorization
    }
}

在Swift中(用户Michael Marvick建议更新,但出于某种原因拒绝了......):

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    if (status == CLAuthorizationStatus.denied) {
        // The user denied authorization
    } else if (status == CLAuthorizationStatus.authorizedAlways) {
        // The user accepted authorization
    } 
}

答案 1 :(得分:6)

Swift 3

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    if (status == CLAuthorizationStatus.denied) {
        // The user denied authorization
    } else if (status == CLAuthorizationStatus.authorizedAlways) {
        // The user accepted authorization
    } 
}

答案 2 :(得分:5)

当位置的授权状态发生变化时,将调用委托方法didChangeAuthorizationStatus:

安装应用后第一次调用requestWhenInUseAuthorization时,将调用状态为kCLAuthorizationStatusNotDetermined(0)的委托方法。

如果用户拒绝了位置服务访问权限,则将再次调用委托方法,状态为kCLAuthorizationStatusDenied(2)。

如果用户批准了位置服务访问权限,则将再次调用委托方法,状态为kCLAuthorizationStatusAuthorizedAlways(3)或kCLAuthorizationStatusAuthorizedWhenInUse(4),具体取决于所请求的权限。

在您的应用的后续执行中,根据当前的位置服务权限,调用kCLAuthorizationStatusDenied后,委托方法将收到状态kCLAuthorizationStatusAuthorizedAlwayskCLAuthorizationStatusAuthorizedWhenInUse / requestWhenInUseAuthorization设备设置中的应用程序。

答案 3 :(得分:4)

此解决方案在所有情况下都不是最好的,但它对我有用,所以我想我会分享:

import Foundation
import CoreLocation

class LocationManager: NSObject, CLLocationManagerDelegate {
    static let sharedInstance = LocationManager()
    private var locationManager = CLLocationManager()
    private let operationQueue = OperationQueue()

    override init(){
        super.init()

        //Pause the operation queue because
        // we don't know if we have location permissions yet
        operationQueue.isSuspended = true
        locationManager.delegate = self
    }

    ///When the user presses the allow/don't allow buttons on the popup dialogue
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

        //If we're authorized to use location services, run all operations in the queue
        // otherwise if we were denied access, cancel the operations
        if(status == .authorizedAlways || status == .authorizedWhenInUse){
            self.operationQueue.isSuspended = false
        }else if(status == .denied){
            self.operationQueue.cancelAllOperations()
        }
    }

    ///Checks the status of the location permission
    /// and adds the callback block to the queue to run when finished checking
    /// NOTE: Anything done in the UI should be enclosed in `DispatchQueue.main.async {}`
    func runLocationBlock(callback: @escaping () -> ()){

        //Get the current authorization status
        let authState = CLLocationManager.authorizationStatus()

        //If we have permissions, start executing the commands immediately
        // otherwise request permission
        if(authState == .authorizedAlways || authState == .authorizedWhenInUse){
            self.operationQueue.isSuspended = false
        }else{
            //Request permission
            locationManager.requestAlwaysAuthorization()
        }

        //Create a closure with the callback function so we can add it to the operationQueue
        let block = { callback() }

        //Add block to the queue to be executed asynchronously
        self.operationQueue.addOperation(block)
    }
}

现在,每当您想要使用位置信息时,只需将其包围:

LocationManager.sharedInstance.runLocationBlock {
    //insert location code here
}

因此,每当您尝试使用位置信息时,都会检查授权状态。如果您还没有权限,它会请求权限并等待用户按下“允许”按钮或“不允许”按钮。如果按下“允许”按钮,任何位置数据请求都将在不同的线程上处理,但如果按下“不允许”按钮,则所有位置请求都将被取消。

答案 4 :(得分:0)

目标C

对于didChangeAuthorizationStatus上的块回调,请在 .h

中添加
@property void(^authorizationCompletionBlock)(BOOL);

并在 .m

中关注
-(void)locationManager:(CLLocationManager *)locationManager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
_authorizationStatus = status;

switch (status) {
    case kCLAuthorizationStatusAuthorizedAlways:
    case kCLAuthorizationStatusAuthorizedWhenInUse:
        if (self.authorizationCompletionBlock) {
            self.authorizationCompletionBlock(YES); // this fires block
        }
    default:
        if (self.authorizationCompletionBlock) {
            self.authorizationCompletionBlock(NO); // this fires block
        }
        break;
    }
}

并添加这样的处理程序:

// this listens block
// in your VC or Utility class
authorizationCompletionBlock = ^(BOOL isGranted) {
    completionBlock(isGranted);
};

Swift 3.2

var authorizationCompletionBlock:((Bool)->())? = {_ in}


func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    switch (status)
    {
    case (.authorizedWhenInUse):
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

    default:
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(false);
        }
    }
}

和像这样的处理程序

authorizationCompletionBlock = { isGranted in
        print(isGranted)
    }

答案 5 :(得分:0)

类似于上述tdon的响应,我创建了一个带有完成块的函数,用于在从设备中检索到状态后传达状态:

func retrieveAuthorizationStatus(completion: @escaping (TrackingState) -> ()) {
    let status = CLLocationManager.authorizationStatus()
    switch status {
    case .authorizedWhenInUse:
        completion(.off)
    default:
        completion(.issue)
    }
}

TrackingState是一个单独的枚举,我正在使用它来管理视图控制器中的显示。您可以轻松地在完成代码块中传递authorizationStatus():

func retrieveAuthorizationStatus(completion: @escaping (CLAuthorizationStatus) -> ()) {
    let status = CLLocationManager.authorizationStatus()
    completion(status)
}