【问题标题】:CLLocationManager AuthorizationStatus callback?CLLocationManager AuthorizationStatus 回调?
【发布时间】:2015-01-14 23:37:54
【问题描述】:

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

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

我试过这个:

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

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

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

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

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    您可以使用 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
        } 
    }
    

    【讨论】:

    • 谢谢,我试过了,但是这个方法永远不会触发。我做了一个简单的 println("test") 没有任何 if 语句,但它不起作用。我目前正在尝试集成一个 NSNotificationCentre 位,因为似乎当显示警报时,应用程序变得不活动。解除警报后,应用程序委托方法 applicationDidBecomeActive 将触发。如果我得到这个工作,我会回复。
    • @matcartmill 您是否在类中包含了 CLLocationManagerDelegate 并将 CLLocationManager 的委托设置为 self?
    • 是的,我有。我在 viewDidLoad 区域中将 locationManager.delegate 设置为 self。这是我的 LocationManager func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus!) { println("Changed") } 它不打印任何东西。
    • 糟糕!我意识到我添加了一个!到我的功能。删除它,现在它正在工作。比添加通知中心功能要好得多。
    • kCLAuthorizationStatusAuthorized 已弃用,请使用 kCLAuthorizationStatusAuthorizedAlways 或 kCLAuthorizationStatusAuthorizedWhenInUse。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      【讨论】:

        【解决方案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
        }
        

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            Swift 5 中的工作代码:

            Plist:添加条目

            <key>NSLocationWhenInUseUsageDescription</key>
              <string>Needs Location when in use</string>
            
            
            import UIKit
            import CoreLocation
            
            class ViewController: UIViewController {
                var locationManager: CLLocationManager?
                
                override func viewDidLoad() {
                    super.viewDidLoad()
                    
                    locationManager = CLLocationManager()
                    
                    //Make sure to set the delegate, to get the call back when the user taps Allow option
                    locationManager?.delegate = self
                }
            }
            
            extension ViewController: CLLocationManagerDelegate {
                func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
                    switch status {
                    case .notDetermined:
                        print("not determined - hence ask for Permission")
                        manager.requestWhenInUseAuthorization()
                    case .restricted, .denied:
                        print("permission denied")
                    case .authorizedAlways, .authorizedWhenInUse:
                        print("Apple delegate gives the call back here once user taps Allow option, Make sure delegate is set to self")
                    }
                }
            }
            

            【讨论】:

              【解决方案7】:

              与上面 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)
              }
              

              【讨论】:

                猜你喜欢
                • 2021-01-12
                • 1970-01-01
                • 2015-12-21
                • 1970-01-01
                • 2012-01-25
                • 2021-10-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多