【问题标题】:How can I prompt the user to turn on location services after user has denied their use用户拒绝使用后如何提示用户打开位置服务
【发布时间】:2011-06-20 23:42:33
【问题描述】:

我有一个使用用户当前位置的显式用户交互的应用程序。如果用户拒绝访问位置服务,我仍然希望后续使用提示用户转到设置并为我的应用重新启用位置服务。

我想要的是内置地图应用程序的行为:

  1. 在“设置”>“常规”>“重置”>“重置位置警告”中重置位置警告。
  2. 启动地图应用。
  3. 点击左下角的当前位置按钮。
  4. 地图提示“地图”希望使用您当前的位置”| “不允许” | “允许”。
  5. 选择“不允许”选项。
  6. 再次点击左下角的当前位置按钮。
  7. 地图提示“打开定位服务以允许“地图”确定您的位置”| “设置” | “取消”。

在我自己的应用程序中,相同的基本流程导致我的 CLLocationManagerDelegate -locationManager:didFailWithError: 在最后一步调用方法时出现 kCLErrorDenied 错误,并且用户无法选择打开设置应用程序来更正它。

我可以显示自己的警报来响应错误,但它无法启动设置应用程序,就像操作系统可以提供的警报一样,内置地图应用程序使用。

我缺少的 CLLocationManager 类中有什么东西可以给我这种行为吗?

【问题讨论】:

  • 现在,我只是向用户显示一个警报,要求他们转到“设置”以重新启用它。我也很想听听更好的解决方案。
  • 我也想要一个答案,肯定有更好的方法
  • 因为这个原因,我发现 CoreLocation 并不令人满意。我最终使用了易于集成且有据可查的 Skyhook 库。坐标似乎也更精确。唯一的缺点是必须将 1.5MB 的 dylib 与应用程序捆绑在一起。
  • 我认为很多答案都显示了stackoverflow.com/questions/5655674/…的答案

标签: ios core-location


【解决方案1】:

基于上述答案的最新 swift 版本。

func showSettingsAlert(_ from:UIViewController, title:String?, message:String?) {

        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil)

        let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .default) { (UIAlertAction) in

            guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
                return
            }

            if UIApplication.shared.canOpenURL(settingsUrl) {
                UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil)
            }
        }

        alertController.addAction(cancelAction)
        alertController.addAction(settingsAction)
        from.present(alertController, animated: true, completion: nil)
    }

【讨论】:

    【解决方案2】:

    斯威夫特

    一旦您禁用应用的定位服务,定位管理器委托方法将开始显示错误。因此,在收到错误时,我们可以检查位置服务是否启用/禁用。根据结果​​,我们可以要求用户进入设置并打开位置服务。

    在您的位置管理器委托方法中,添加位置权限检查

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                //check  location permissions
                self.checkLocationPermission()
            }
    }
    

    位置权限检查代码

    //check location services enabled or not
    
        func checkLocationPermission() {
            if CLLocationManager.locationServicesEnabled() {
                switch(CLLocationManager.authorizationStatus()) {
                case .notDetermined, .restricted, .denied:
                    //open setting app when location services are disabled
                openSettingApp(message:NSLocalizedString("please.enable.location.services.to.continue.using.the.app", comment: ""))
                case .authorizedAlways, .authorizedWhenInUse:
                    print("Access")
                }
            } else {
                print("Location services are not enabled")
                openSettingApp(message:NSLocalizedString("please.enable.location.services.to.continue.using.the.app", comment: ""))
            }
        }
    

    打开设置应用的代码,

    //open location settings for app
    func openSettingApp(message: String) {
        let alertController = UIAlertController (title: APP_NAME_TITLE, message:message , preferredStyle: .alert)
    
        let settingsAction = UIAlertAction(title: NSLocalizedString("settings", comment: ""), style: .default) { (_) -> Void in
            guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
                return
            }
    
            if UIApplication.shared.canOpenURL(settingsUrl) {
                UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil)
            }
        }
        alertController.addAction(settingsAction)
        let cancelAction = UIAlertAction(title: NSLocalizedString("cancel", comment: ""), style: .default, handler: nil)
        alertController.addAction(cancelAction)
    
        present(alertController, animated: true, completion: nil)
    }
    

    【讨论】:

      【解决方案3】:

      在 Swift 4 中,它的语法有所更新。

      斯威夫特 4

      extension UIAlertController {
      
          func createSettingsAlertController(title: String, message: String) {
      
            let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
      
            let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil)
            let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .default) { (UIAlertAction) in
              UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)! as URL, options: [:], completionHandler: nil)
            }
      
            alertController.addAction(cancelAction)
            alertController.addAction(settingsAction)
            self.present(alertController, animated: true, completion: nil)
      
         }
      }
      

      【讨论】:

        【解决方案4】:

        用于创建设置警报控制器的 Swift 3 扩展:

        导入基础

        extension UIAlertController {
            func createSettingsAlertController(title: String, message: String) -> UIAlertController {
                let controller = UIAlertController(title: title, message: message, preferredStyle: .alert)
        
                let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment:"" ), style: .cancel, handler: nil)
                let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment:"" ), style: .default, handler: { action in
                    UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
                })
                controller.addAction(cancelAction)
                controller.addAction(settingsAction)
        
                return controller
            }
        }
        

        【讨论】:

          【解决方案5】:

          这里是Markus和bjc提供的代码的swift 3实现。

          let alertController = UIAlertController(title: NSLocalizedString("Enter your title here", comment: ""), message: NSLocalizedString("Enter your message here.", comment: ""), preferredStyle: .alert)
          
          let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil)
          let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .default) { (UIAlertAction) in
                          UIApplication.shared.openURL(NSURL(string: UIApplicationOpenSettingsURLString)! as URL)
                      }
          
          alertController.addAction(cancelAction)
          alertController.addAction(settingsAction)
                      self.present(alertController, animated: true, completion: nil)
          

          【讨论】:

            【解决方案6】:

            这是 Markus 答案中代码的 Swift 版本。此代码会创建一个警报,让用户可以选择打开“设置”。

            let alertController = UIAlertController(title: NSLocalizedString("Enter your title here", comment: ""), message: NSLocalizedString("Enter your message here.", comment: ""), preferredStyle: .Alert)
            
            let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil)
            let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .Default) { (UIAlertAction) in
                UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
            }
            
            alertController.addAction(cancelAction)
            alertController.addAction(settingsAction)
            self.presentViewController(alertController, animated: true, completion: nil)
            

            【讨论】:

              【解决方案7】:

              更新:

              从 iOS 8 开始,现在有一个常量 UIApplicationOpenSettingsURLString,它表示一个 URL,当打开该 URL 时,会打开 Settings 应用程序以访问应用程序的设置(然后用户可以在其中重新启用位置服务)。


              原文:

              你没有办法做到这一点。您唯一真正的选择是显示一条警报,通知用户您的应用程序需要定位服务,并指示他们手动转到“设置”应用程序并将其打开。

              【讨论】:

              • 我已经阅读了 Apple Docs 并根据文档在下面发布了答案,但我没有自己测试过。这是 SDK 的变化还是相同。
              • 恐怕这个答案不再正确。您可能希望更新或删除您的答案。
              • 这是 Swift nshipster.com/core-location-in-ios-8 的一个很好的例子,我发现它真的很有帮助。它展示了如何使用UIApplicationOpenSettingsURLString 发出重定向到Settings 的警报。
              【解决方案8】:

              AlertViews 在 iOS 8 中被弃用。现在使用新的 AlertController 可以更好地处理警报:

              UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString( @"Enter your title here", @"" ) message:NSLocalizedString( @"Enter your message here.", @"" ) preferredStyle:UIAlertControllerStyleAlert];
              
              UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Cancel", @"" ) style:UIAlertActionStyleCancel handler:nil];
              UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Settings", @"" ) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
                 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:
                                                                  UIApplicationOpenSettingsURLString]];
              }];
              
              [alertController addAction:cancelAction];
              [alertController addAction:settingsAction];
              
              [self presentViewController:alertController animated:YES completion:nil];
              

              【讨论】:

                【解决方案9】:

                使用 iOS8,您终于可以通过 openURL 将用户链接到设置应用程序。例如,您可以创建一个带有单个按钮的 UIAlertView,将用户带到设置应用程序:

                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ICLocalizedString(@"LocationServicesPermissionTitle")
                                                                    message:ICLocalizedString(@"LocationPermissionGeoFenceMessage")
                                                                   delegate:self
                                                          cancelButtonTitle:@"Settings"
                                                          otherButtonTitles:nil];
                    [alert show];
                

                在您的 UIAlertView 委托中:

                - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
                    [alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
                    [[UIApplication sharedApplication] openURL: [NSURL URLWithString: UIApplicationOpenSettingsURLString]];
                }
                

                【讨论】:

                • 这比在 iOS 7 和更早的版本中做的要好得多,但仍然不完美,因为 URL 会将您带到用户可以实际更改设置的上一级屏幕。跨度>
                • 至少从 iOS 10 开始,它会将您带到应用设置,其中还列出了位置。
                【解决方案10】:

                根据 locationServicesEnabled 方法上的Apple's Docs

                用户可以在“设置”应用程序中通过切换“位置服务”开关来启用或禁用位置服务。

                您应该在开始位置更新之前检查此方法的返回值,以确定用户是否为当前设备启用了位置服务。 如果此方法返回 NO 并且您仍然开始位置更新,Core Location 框架会提示用户确认是否应重新启用位置服务。

                所以你不能以任何方式启动位置服务更新来提示警报吗?

                【讨论】:

                • 这种方式并不真正起作用,可能与 locationServicesEnabled 和 authorized 之间的细微区别有关。如果它们被禁用,它会提示启用,但如果它们被启用但被拒绝,它将什么也不做。不过,这是非常令人困惑的文档。
                • locationServicesEnabled 是一个已弃用的方法。
                【解决方案11】:

                我想当 Apple 考虑新的 SDK 时,您的问题就会得到答案。目前,据我所知,这是不可能的:

                没有可用的 URL 处理程序
                没有可用的调用方法

                但是...正如 Maps 所做的那样,这可以完成,但可能使用私有 API。如果你不害怕这种编码,我认为你应该在那里搜索。

                【讨论】:

                  猜你喜欢
                  • 2015-10-04
                  • 2011-08-25
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-08-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多