在 iOS 上检查位置服务权限

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15153074/
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-30 22:31:02  来源:igfitidea点击:

Checking location service permission on iOS

iosobjective-cswiftcllocationmanager

提问by Melih Mucuk

How can I check if location service is enabled for my app?

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

I have 2 storyboards and I want to check location service. If location service enabled for my app, I want to launch map storyboard with location. Otherwise, I want to launch another storyboard. How can I do programmatically?

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

回答by Melih Mucuk

This is the correct.

这是正确的。

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];
    }
}

回答by swiftBoy

Tested on iOS 9.2

在 iOS 9.2 上测试

For getting location updates we should always check

为了获取位置更新,我们应该始终检查

  • Location services enabled on user's iOS Device and
  • Location services enabled for particular app
  • 在用户的 iOS 设备上启用位置服务和
  • 为特定应用启用定位服务

and launching user on correct settings screen to enable

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

Launch iOS Device Location Settings page

启动 iOS 设备位置设置页面

Step.1 Go to Project settings --> Info --> URL Types --> Add New URL Schemes

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

enter image description here

在此处输入图片说明

Step.2 Use below code to launch direct phone's location settings page: (Note: The URL Scheme is different in iOS 10+, we check the version as stated here)

Step.2 使用下面的代码来启动直接手机的位置设置页面:(注意:URL Scheme 在 iOS 10+ 中是不同的,我们在这里检查版本)

 #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]];

enter image description here

在此处输入图片说明

Launch Application Location Settings page

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

Use below code to launch direct application's location settings page

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

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

enter image description here

在此处输入图片说明

Here is the full code example :

这是完整的代码示例:

#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];
    }
}

Handle the user click respone, and launch correct location settings

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

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

回答by Virus

-(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];
        }
    }
 }

Reason behind this, this method will call when your service will be disable the location service. this code is useful for me.

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

回答by Sumit Mundra

Check CLLocationManager's locationServicesEnabledproperty to check the system-wide availability. Use your CLLocationManagerDelegate's locationManager: didFailWithError:method and check for a kCLErrorDeniederror to see if the user denied location services.

检查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];
}

for your app use this code

对于您的应用程序,请使用此代码

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

if location service disable for your app then its give you error

如果您的应用程序禁用位置服务,那么它会给您错误

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

回答by hasan

After a lot of investigation. I would recommend to display this message on a label and not on an alert view. because, there are a lot of cases to test against(user disables location service in general or just for app. delete app, reinstall).

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

One of these cases causes your alert to show your message along with apple's alert message at the same time. your alert will be behind apple's alert. which is a confusing and un-logical behavior.

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

I recommend the following:

我推荐以下内容:

Swift 3:

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

Objective-C:

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

回答by Kakshil Shah

The best way, handling all cases! ->

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

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

回答by Sourabh Sharma



Swift 3.0 & iOS 10 Solution:

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
    }

}

回答by Pooja Gupta

Updated in Latest Swift 5.0, Xcode 11.2.1

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

import UIKit
import CoreLocation

User constants

用户常量

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

Location Manager Delegate for monitoring location changes

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

Location updates with authorization check

带有授权检查的位置更新

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

Show location alert if permission is not allowed

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

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

}

For testing above, just write these line of code in your controller,

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

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

LocationManagerDelegate Methods

LocationManagerDelegate 方法

extension ViewController: LocationManagerDelegate {

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

}