【问题标题】:Checking location service permission on iOS在 iOS 上检查位置服务权限
【发布时间】:2013-02-15 16:18:05
【问题描述】:

如何检查我的应用是否启用了定位服务?

我有 2 个故事板,我想检查定位服务。如果为我的应用启用了位置服务,我想启动带有位置的地图故事板。否则,我想启动另一个故事板。如何以编程方式进行?

【问题讨论】:

    标签: ios objective-c swift cllocationmanager


    【解决方案1】:

    检查 CLLocationManager 的 locationServicesEnabled 属性以检查系统范围的可用性。使用您的 CLLocationManagerDelegate 的 locationManager: didFailWithError: 方法并检查 kCLErrorDenied 错误以查看用户是否拒绝了位置服务。

    BOOL locationAllowed = [CLLocationManager locationServicesEnabled];
     if (!locationAllowed) 
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location Service Disabled" 
                                                            message:@"To re-enable, please go to Settings and turn on Location Service for this app." 
                                                           delegate:nil 
                                                  cancelButtonTitle:@"OK" 
                                                  otherButtonTitles:nil];
            [alert show];
            [alert release];
    }
    

    为您的应用使用此代码

    - (void)viewDidLoad
    {
        locationManager = [[CLLocationManager alloc] init];
    
        locationManager.delegate = self;
    
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    
        // Set a movement threshold for new events.
    
        locationManager.distanceFilter = 500;
    
        [locationManager startUpdatingLocation];
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)locationManager:(CLLocationManager *)manager
    
         didUpdateLocations:(NSArray *)locations {
    
        // If it's a relatively recent event, turn off updates to save power
    
    }
    
    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
    
        NSLog(@"%@",error);
    }
    

    如果您的应用禁用了定位服务,那么它会给您错误

    Error Domain=kCLErrorDomain Code=1 "The operation couldn’t be completed. (kCLErrorDomain error 1.)"
    

    【讨论】:

    • 我把这段代码放在viewDidLoad中,locationAllowed总是返回YES。
    • 此代码检查主要位置服务权限。我要求检查应用程序权限。缺少此代码。
    【解决方案2】:

    这是正确的。

    if ([CLLocationManager locationServicesEnabled]){
    
        NSLog(@"Location Services Enabled");
    
        if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied){
            alert = [[UIAlertView alloc] initWithTitle:@"App Permission Denied"     
                                               message:@"To re-enable, please go to Settings and turn on Location Service for this app." 
                                              delegate:nil 
                                     cancelButtonTitle:@"OK" 
                                     otherButtonTitles:nil];
            [alert show];
        }
    }
    

    【讨论】:

    • 如果您需要通知用户请求某人为他们启用它,请检查 kCLAuthorizationStatusRestricted。
    • 如果您错误地配置了您的应用程序(例如,拼错了 NSLocationsAlwaysUsageDescription),那么 locationServicesEnabled 似乎仍然返回 true。检查 locationManager:didChangeAuthorizationStatus: 似乎检测到该问题。
    • @Melih Mucuk 不应该将NSLog 语句放在if```` statement called authorizationStatus 之后的else 语句中```?
    • 经过大量调查。我建议在标签上显示此消息。不使用警报视图。因为,有很多情况要测试(删除应用程序,重新安装它,一般禁用位置服务或仅用于应用程序。重新删除,重新安装......)。其中一种情况会导致同时显示您的警报消息和苹果的警报消息。您的警报将落后于苹果警报。这是一种令人困惑且不合逻辑的行为。我在下面添加了一个答案。
    • 它总是返回是,我没有给出允许位置
    【解决方案3】:
    -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    
        NSLog(@"%@",error.userInfo);
        if([CLLocationManager locationServicesEnabled]){
    
            NSLog(@"Location Services Enabled");
    
            if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied){
             UIAlertView    *alert = [[UIAlertView alloc] initWithTitle:@"App Permission Denied"
                                                   message:@"To re-enable, please go to Settings and turn on Location Service for this app."
                                                  delegate:nil
                                         cancelButtonTitle:@"OK"
                                         otherButtonTitles:nil];
                [alert show];
            }
        }
     }
    

    这背后的原因,当您的服务将禁用位置服务时,此方法将调用。这段代码对我很有用。

    【讨论】:

      【解决方案4】:

      经过大量调查。我建议在标签上而不是在警报视图上显示此消息。因为,有很多情况需要测试(用户一般禁用定位服务或仅针对应用。删除应用,重新安装)。

      其中一种情况会导致您的警报同时显示您的消息和苹果的警报消息。您的警报将落后于苹果的警报。这是一种令人困惑且不合逻辑的行为。

      我建议如下:

      斯威夫特 3:

      func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
      
          switch status {
              case .notDetermined:
                  Log.verbose("User still thinking granting location access!")
                  manager.startUpdatingLocation() // this will access location automatically if user granted access manually. and will not show apple's request alert twice. (Tested)
              break
      
              case .denied:
                  Log.verbose("User denied location access request!!")
                  // show text on label
                  label.text = "To re-enable, please go to Settings and turn on Location Service for this app."
      
                  manager.stopUpdatingLocation()
                  loadingView.stopLoading()
              break
      
              case .authorizedWhenInUse:
                  // clear text
                  label.text = ""
                  manager.startUpdatingLocation() //Will update location immediately
              break
      
              case .authorizedAlways:
                  // clear text
                  label.text = ""
                  manager.startUpdatingLocation() //Will update location immediately
              break
              default:
                  break
          }
      }
      

      目标-C:

      - (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
          switch (status) {
              case kCLAuthorizationStatusNotDetermined: {
                  DDLogVerbose(@"User still thinking granting location access!");
                  [locationManager startUpdatingLocation]; // this will access location automatically if user granted access manually. and will not show apple's request alert twice. (Tested)
              } break;
              case kCLAuthorizationStatusDenied: {
                  DDLogVerbose(@"User denied location access request!!");
                  // show text on label
                  label.text = @"To re-enable, please go to Settings and turn on Location Service for this app.";
      
                  [locationManager stopUpdatingLocation];
                  [loadingView stopLoading];
              } break;
              case kCLAuthorizationStatusAuthorizedWhenInUse:
              case kCLAuthorizationStatusAuthorizedAlways: {
                  // clear text
                  label.text = @"";
                  [locationManager startUpdatingLocation]; //Will update location immediately
              } break;
              default:
                  break;
          }
      }
      

      【讨论】:

        【解决方案5】:

        在 iOS 9.2 上测试

        为了获取位置更新,我们应该经常检查

        • 在用户的 iOS 设备上启用了定位服务,并且
        • 为特定应用启用定位服务

        并在正确的设置屏幕上启动用户以启用

        启动 iOS 设备位置设置页面

        Step.1 转到项目设置 --> 信息 --> URL 类型 --> 添加新的 URL 方案

        Step.2 使用以下代码启动直接电话的位置设置页面: (注意:iOS 10+ 中的 URL Scheme 不同,我们检查版本here

         #define SYSTEM_VERSION_LESS_THAN(v)  ([[[UIDevice 
         currentDevice] systemVersion] compare:v options:NSNumericSearch] == 
         NSOrderedAscending)
        
         //Usage
        NSString* url = SYSTEM_VERSION_LESS_THAN(@"10.0") ? @"prefs:root=LOCATION_SERVICES" : @"App-Prefs:root=Privacy&path=LOCATION";
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString: url]];
        

        启动应用程序位置设置页面

        使用以下代码启动直接应用程序的位置设置页面

        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        

        这是完整的代码示例:

        #define SYSTEM_VERSION_LESS_THAN(v)  ([[[UIDevice 
         currentDevice] systemVersion] compare:v options:NSNumericSearch] == 
         NSOrderedAscending)
        
        
        CLLocationManager *locationManager;
        
        -(void) checkLocationServicesAndStartUpdates
        {
            locationManager = [[CLLocationManager alloc] init];
            locationManager.delegate = self;
            locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        
            if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
            {
                [locationManager requestWhenInUseAuthorization];
            }
        
            //Checking authorization status
            if (![CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied)
            {
        
                UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Location Services Disabled!"
                                                                    message:@"Please enable Location Based Services for better results! We promise to keep your location private"
                                                                   delegate:self
                                                          cancelButtonTitle:@"Settings"
                                                          otherButtonTitles:@"Cancel", nil];
        
                //TODO if user has not given permission to device
                if (![CLLocationManager locationServicesEnabled])
                {
                    alertView.tag = 100;
                }
                //TODO if user has not given permission to particular app
                else
                {
                    alertView.tag = 200;
                }
        
                [alertView show];
        
                return;
            }
            else
            {
                //Location Services Enabled, let's start location updates
                [locationManager startUpdatingLocation];
            }
        }
        

        处理用户点击响应,并启动正确的位置设置

        -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
        {
        
            if(buttonIndex == 0)//Settings button pressed
            {
                if (alertView.tag == 100)
                {
                    //This will open ios devices location settings
                    NSString* url = SYSTEM_VERSION_LESS_THAN(@"10.0") ? @"prefs:root=LOCATION_SERVICES" : @"App-Prefs:root=Privacy&path=LOCATION";
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString: url]];
                }
                else if (alertView.tag == 200)
                {
                    //This will opne particular app location settings
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
                }
            }
            else if(buttonIndex == 1)//Cancel button pressed.
            {
                //TODO for cancel
            }
        }
        

        【讨论】:

        • if (![CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) 中的 && 不应该是 OR (||)
        • 这应该像疯了一样被投票!迄今为止最快、最简单的解决方案!
        • 谢谢@greenhouse,我很高兴它对你有帮助:)
        【解决方案6】:

        最好的办法,处理所有情况! ->

        //First, checking if the location services are enabled
        if(![CLLocationManager locationServicesEnabled]){
            [self showMessage:@"Please enable location services to detect location!" withTitle:@"Location not enabled"];
        }
        else if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied){
            //Now if the location is denied.
            UIAlertController *alertController = [UIAlertController
                                                  alertControllerWithTitle:@"Enable location permission"
                                                  message:@"To auto detect location, please enable location services for this app"
                                                  preferredStyle:UIAlertControllerStyleAlert];
        
            alertController.view.tintColor = AppColor;
            UIAlertAction *cancelAction = [UIAlertAction
                                           actionWithTitle:@"Dismiss"
                                           style:UIAlertActionStyleCancel
                                           handler:^(UIAlertAction *action)
                                           {
                                                NSLog(@"Cancel action");
                                           }];
        
            UIAlertAction *goToSettings = [UIAlertAction
                                        actionWithTitle:@"Settings"
                                        style:UIAlertActionStyleDefault
                                        handler:^(UIAlertAction *action)
                                        {
                                            //Simple way to open settings module
                                            NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                                            [[UIApplication sharedApplication] openURL:url];
                                        }];
        
            [alertController addAction:cancelAction];
            [alertController addAction:goToSettings];
            [self presentViewController:alertController animated:YES completion:^{
                alertController.view.tintColor = AppColor;
            }];
        }
        else{
            //Do whatever you want here
        }
        

        【讨论】:

          【解决方案7】:

          Swift 3.0 & iOS 10 解决方案:


          self.locationManager?.requestWhenInUseAuthorization()
          if CLLocationManager.locationServicesEnabled() && CLLocationManager.authorizationStatus() != CLAuthorizationStatus.denied {
                      locationManager?.delegate = self
                      locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
                      locationManager?.distanceFilter = distanceFiler
                      locationManager?.startUpdatingLocation()
                  }else{
                      let alertView = UIAlertView(title: "Location Services Disabled!", message: "Please enable Location Based Services for better results! We promise to keep your location private", delegate: self, cancelButtonTitle: "Settings", otherButtonTitles: "Cancel")
                      alertView.delegate = self
                      alertView.show()
                      return
                  }
          
          
          @objc(alertView:clickedButtonAtIndex:) func alertView(_ alertView: UIAlertView, clickedButtonAt buttonIndex: Int) {
              if buttonIndex == 0 {
                      if let url = URL(string: "App-Prefs:root=LOCATION_SERVICES") {
                          UIApplication.shared.open(url, completionHandler: .none)
                      }
              }
              else if buttonIndex == 1 {
                  //TODO for cancel
              }
          
          }
          

          【讨论】:

            【解决方案8】:

            在最新的 Swift 5.0、Xcode 11.2.1 中更新

            import UIKit
            import CoreLocation
            

            用户常量

            struct UserConstants {
                static let latitude = "latitude"
                static let longitude = "longitude"
                static let lastKnownLatitude = "lastKnownLatitude"
                static let lastKnownLongitude = "lastKnownLongitude"
            }
            

            Location Manager Delegate 用于监控位置变化

            @objc protocol LocationManagerDelegate {
                @objc optional func getLocation(location: CLLocation)
            }
            
            class LocationHelper: NSObject, CLLocationManagerDelegate {
            
                weak var locationManagerDelegate: LocationManagerDelegate?
                var isLocationfetched: Bool = false
                var lastKnownLocation: CLLocation? {
                    get {
                        let latitude = UserDefaults.standard.double(forKey: UserConstants.lastKnownLatitude)
                        let longitude = UserDefaults.standard.double(forKey: UserConstants.lastKnownLongitude)
            
                        if latitude.isZero || longitude.isZero {
                            return nil
                        }
                        return CLLocation(latitude: latitude, longitude: longitude)
                    }
                    set {
                        UserDefaults.standard.set(newValue?.coordinate.latitude ?? 0, forKey: UserConstants.lastKnownLatitude)
                        UserDefaults.standard.set(newValue?.coordinate.longitude ?? 0, forKey: UserConstants.lastKnownLongitude)
                        UserDefaults.standard.synchronize()
                    }
                }
            
                struct SharedInstance {
                    static let instance = LocationHelper()
                }
            
                class var shared: LocationHelper {
                    return SharedInstance.instance
                }
            
                enum Request {
                    case requestWhenInUseAuthorization
                    case requestAlwaysAuthorization
                }
            
                var clLocationManager = CLLocationManager()
            
                func setAccuracy(clLocationAccuracy: CLLocationAccuracy) {
                    clLocationManager.desiredAccuracy = clLocationAccuracy
                }
            
                var isLocationEnable: Bool = false {
                    didSet {
                        if !isLocationEnable {
                            lastKnownLocation = nil
                        }
                    }
                }
            

            带有授权检查的位置更新

                func startUpdatingLocation() {
                    isLocationfetched = false
                    if CLLocationManager.locationServicesEnabled() {
                        switch CLLocationManager.authorizationStatus() {
                        case .notDetermined:
                            clLocationManager.delegate = self
                            clLocationManager.requestWhenInUseAuthorization()
                            clLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
                            clLocationManager.startUpdatingLocation()
                            isLocationEnable = true
                        case .restricted, .denied:
                            showLocationAccessAlert()
                            isLocationEnable = false
                        case .authorizedAlways, .authorizedWhenInUse:
                            self.clLocationManager.delegate = self
                            self.clLocationManager.startUpdatingLocation()
                            isLocationEnable = true
                        default:
                            print("Invalid AuthorizationStatus")
                        }
                    } else {
                        isLocationEnable = false
                        showLocationAccessAlert()
                    }
                }
            

            如果不允许,则显示位置警报

                func showLocationAccessAlert() {
                    let alertController = UIAlertController(title: "Location Permission Required", message: "Please enable location permissions in settings.", preferredStyle: UIAlertController.Style.alert)
                    let okAction = UIAlertAction(title: "settings", style: .default, handler: {(cAlertAction) in
                        UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
                    })
                    let cancelAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.cancel)
                    alertController.addAction(cancelAction)
                    alertController.addAction(okAction)
                    let appdelegate = UIApplication.shared.delegate as? AppDelegate
                    appdelegate?.window?.rootViewController?.present(alertController, animated: true, completion: nil)
                }
            
                func stopUpdatingLocation() {
                    self.clLocationManager.stopUpdatingLocation()
                }
            
                func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
                    if !isLocationfetched {
                        isLocationfetched = true
                        clLocationManager.startMonitoringSignificantLocationChanges()
                        NotificationCenter.default.post(name: NSNotification.Name.updateLocationNotification, object: nil)
                    }
                    let userLocation = locations[0] as CLLocation
                    self.lastKnownLocation = userLocation
                    if let delegate = self.locationManagerDelegate {
                        delegate.getLocation!(location: userLocation)
                    }
                }
            
                func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
                    if (status == CLAuthorizationStatus.denied) {
                        // The user denied authorization
                        isLocationEnable = false
                    } else if (status == CLAuthorizationStatus.authorizedWhenInUse) {
                        // The user accepted authorization
                        self.clLocationManager.delegate = self
                        self.clLocationManager.startUpdatingLocation()
                        isLocationEnable = true
                    }
                }
            
                func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
                    print("\n error description for location updation:- \(error.localizedDescription)")
                }
            
            }
            

            对于上面的测试,只需在控制器中编写这些代码行,

            LocationHelper.shared.locationManagerDelegate = self
            LocationHelper.shared.startUpdatingLocation()
            

            LocationManagerDelegate 方法

            extension ViewController: LocationManagerDelegate {
            
                func getLocation(location: CLLocation) {
                    currentLocation = location.coordinate
                }
            
            }
            

            【讨论】:

            • 嗨,在 didUpdateLocation 中委托以下代码行:-“NotificationCenter.default.post(name: NSNotification.Name.updateLocationNotification, object: nil)”显示错误为:-“Type 'NSNotification .Name' 没有成员 'updateLocationNotification'" 请更新它。
            猜你喜欢
            • 2016-09-17
            • 1970-01-01
            • 2020-12-26
            • 2015-02-10
            • 2019-12-31
            • 2016-06-22
            • 2019-03-27
            • 2017-09-20
            • 2016-12-08
            相关资源
            最近更新 更多