ios CLLocationManager AuthorizationStatus 回调?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27954480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 04:21:27  来源:igfitidea点击:

CLLocationManager AuthorizationStatus callback?

iosswift

提问by matcartmill

In my app I have a tab called "Discover". The Discover tab will use the users current location to find "stuff" near them. Instead of presenting the user with a generic Authorization Request (which typically gets declined, based on research), I present the user with a modal explaining what we're asking for. If they say yes, THEN the actual Authorization message pops up.

在我的应用程序中,我有一个名为“发现”的选项卡。“发现”选项卡将使用用户当前位置来查找他们附近的“东西”。我没有向用户呈现通用的授权请求(根据研究通常会被拒绝),而是向用户呈现一个模式,解释我们的要求。如果他们说是,那么实际的授权消息就会弹出。

However, the user still has the option to say no the prompt. Is there a way to add a callback to the prompt so that once the user selects an option I can see if they accepted or declined?

但是,用户仍然可以选择拒绝提示。有没有办法向提示添加回调,以便一旦用户选择一个选项,我就可以看到他们是接受还是拒绝?

I have tried this:

我试过这个:

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

As expected, the "println" executes at the same time that the request prompt comes up, so I can't do it that way.

正如预期的那样,“println”在请求提示出现的同时执行,所以我不能那样做。

The problem is that if the user opts to not use Location Data, the content served will be different than if they had accepted.

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

Ideally I'm hoping for a callback of some kind, but I'll take any logical direction at this point!

理想情况下,我希望有某种回调,但此时我会采取任何合乎逻辑的方向!

回答by Lyndsey Scott

You can use the locationManager:didChangeAuthorizationStatus:CLLocationManagerDelegatemethod as a "callback" of sorts.

您可以将该 方法用作各种“回调”。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
    }
}

And in Swift (update suggested by user Michael Marvick, but rejected for some reason...):

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

回答by user2213459

Swift 3

斯威夫特 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
    } 
}

回答by Paulw11

When the authorisation status for location changes, the delegate method didChangeAuthorizationStatus:will be called.

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

When you call requestWhenInUseAuthorizationthe first time after your app is installed the delegate method will be called with status kCLAuthorizationStatusNotDetermined(0).

当您requestWhenInUseAuthorization在安装应用程序后第一次调用时,委托方法将被调用,状态为kCLAuthorizationStatusNotDetermined(0)。

If the user declines location services access then the delegate method will be called again with status kCLAuthorizationStatusDenied(2).

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

If the user approves location services access then the delegate method will be called again with status kCLAuthorizationStatusAuthorizedAlways(3) or kCLAuthorizationStatusAuthorizedWhenInUse(4) depending on the permission that was requested.

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

On subsequent executions of your app the delegate method will receive status kCLAuthorizationStatusDeniedor kCLAuthorizationStatusAuthorizedAlways/kCLAuthorizationStatusAuthorizedWhenInUseafter calling requestWhenInUseAuthorizationbased on the current state of location services permission for the app in the device settings.

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

回答by tdon

This solution isn't the best in all scenarios, but it worked for me so I thought I'd share:

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

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

Now every time you want to use location information, just surround it with this:

现在每次你想使用位置信息时,只需用这个包围它:

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

So whenever you try using the location information, the authorization status is checked. If you don't have permission yet, it requests permission and waits until the user presses the "Allow" button or the "Don't allow" button. If the "Allow" button is pressed, any requests for location data will be processed on separate threads, but if the "Don't Allow" button is pressed, all location requests will be canceled.

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

回答by Muhammad Waqas

Objective C

目标 C

For a block callback on didChangeAuthorizationStatus add this in .h

对于 didChangeAuthorizationStatus 上的块回调,在.h 中添加它

@property void(^authorizationCompletionBlock)(BOOL);

and following in .m

并在.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;
    }
}

and add handler like this:

并添加这样的处理程序:

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

Swift 3.2

斯威夫特 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);
        }
    }
}

and handler like this

和这样的处理程序

authorizationCompletionBlock = { isGranted in
        print(isGranted)
    }

回答by B-Rad

Similar to tdon's response above, I created a function with a completion block to communicate the status once it is retrieved from the device:

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

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

TrackingState is a separate enum I'm using to manage display within a view controller. You could just as easily pass the authorizationStatus() in the completion block:

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

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