iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式

iOS提供了两个框架用来定位以及地图显示。CoreLocation框架包含的类可以帮助设备确定位置和航向以及使用基于位置的有效信息。MapKit框架未定位提供了户用页面的支持(地图显示),里面包含了地图视图、卫星地图视图以及2D、3D混合视图,并且能够让开发人员管理地图标注和地图覆盖层,前者 用于标注地点(常见的地图大头针),后者用来突出某区域或者路线等。

本期内容:

  • CLLocationManager申请定位权限
  • CLLocationManager获取用户定位
  • CLLocation详细使用,定位数据处理
  • GPX虚拟定位文件的使用以及模拟器定位使用

CLLocationManager 定位管理器

简介:CLLocationManager是用于启动和停止向App获取位置相关的事件的对象。
只有在得到用户许可的情况下,App才能获取设备的当前位置,但是在获取设备位置之前,App还必须确保设备启动了定位服务,当满足这些条件后,App就可以获取启动位置请求的权限并获取当前位置。


CLLocationManager申请定位权限

那我们就开始了,首先要去项目的target里设置info.plist文件字段(苹果的隐私安全需求,不添加是不允许使用的),如下图标注的三个字段:
iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第1张图片
接下来我们开始敲代码,创建一个定位管理器CLLocationManager,但是刚刚我们也说过了,如果系统没有打开定位服务,那么我们获得授权也是没用的,所以,首先判断设备是否打开了定位服务:

    // 1.检查定位服务是否开启
    if ([self checkLocationServiceIsEnabled]) {
        // 2.创建定位管理器:
        [self createCLManager];
    }

检查的内部实现:

- (BOOL)checkLocationServiceIsEnabled{
	// 该方法是类方法,和我们创建的管理器没有关系
    if ([CLLocationManager locationServicesEnabled]) {
        return YES;
    }
    UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"系统定位尚未打开,请到【设定-隐私】中手动打开" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction * tipsAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
    [alertVC addAction:tipsAction];
    [self presentViewController:alertVC animated:YES completion:nil];
    return NO;
}

创建定位管理器内部实现:

- (void)createCLManager{
    // 创建CoreLocation管理对象
    self.locaationManager = [[CLLocationManager alloc]init];
    // 设定定位精准度
    [self.locaationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    // 设定DistanceFilter可以在用户移动指定距离之后触发更新事件(100米更新一次)
    [self.locaationManager setDistanceFilter:100.f];
    // 设置代理
    self.locaationManager.delegate = self;
    // 开始更新定位
    [self.locaationManager startUpdatingLocation];
}

在这里说一下定位的精准度,这是一个枚举,具体的有以下方式:

精准度枚举 作用
kCLLocationAccuracyBestForNavigation 最佳精确度(汽车导航使用)
kCLLocationAccuracyBest 最佳精确度
kCLLocationAccuracyNearestTenMeters 10米误差
kCLLocationAccuracyHundredMeters 百米误差
kCLLocationAccuracyKilometer 千米误差
kCLLocationAccuracyThreeKilometers 三千米误差

这会儿我们的定位管理器就创建好了,但是到了这一步还是没法使用定位,因为,用户还没有授权给我们的App获取定位权限,所以这会儿我们就需要去主动给用户通知,让用户授权,使用的是CLLocationManager的代理方法:

// 代理方法,定位权限检查
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:{
            NSLog(@"用户还未决定授权");
            // 主动获得授权
            [self.locaationManager requestWhenInUseAuthorization];
            break;
        }
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            // 主动获得授权
            [self.locaationManager requestWhenInUseAuthorization];
            break;
        }
        case kCLAuthorizationStatusDenied:{
            // 此时使用主动获取方法也不能申请定位权限
            // 类方法,判断是否开启定位服务 
            if ([CLLocationManager locationServicesEnabled]) {
                NSLog(@"定位服务开启,被拒绝");
            } else {
                NSLog(@"定位服务关闭,不可用");
            }
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:{
            NSLog(@"获得前后台授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:{
            NSLog(@"获得前台授权");
            break;
        }
        default:
            break;
    }
}

在上述方法中,我们使用[self.locaationManager requestWhenInUseAuthorization]去主动获得授权,但也需要注意里面的两个场景是无法获得授权的。

完成了以上步骤,我们就可以获得权限了,然后我们开始去获得定位


CLLocationManager获取用户定位

CLLocationManager在获取定位的时候是通过代理方法实现的,该方法包装了类型为CLLocation的定位数据数组,并返回给代理中,具体实现如下:

// 代理方法,更新位置
-  (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    // locations是一个数组提供了一连串的用户定位,所以在这里我们只取最后一个(当前最后的定位)
    CLLocation * newLocation = [locations lastObject];
    // 判空处理
    if (newLocation.horizontalAccuracy < 0) {
        UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"定位错误,请检查手机网络以及定位" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * tipsAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:tipsAction];
        [self presentViewController:alertVC animated:YES completion:nil];
        return;
    }
    
    // 获取定位经纬度
    CLLocationCoordinate2D coor2D = newLocation.coordinate;
    NSLog(@"纬度为:%f, 经度为:%f", coor2D.latitude, coor2D.longitude);
    
    // 获取定位海拔高度
    CLLocationDistance altitude = newLocation.altitude;
    NSLog(@"高度为:%f", altitude);
    
    // 获取定位水平精确度, 垂直精确度
    CLLocationAccuracy horizontalAcc = newLocation.horizontalAccuracy;
    CLLocationAccuracy verticalAcc = newLocation.verticalAccuracy;
    NSLog(@"%f, %f", horizontalAcc, verticalAcc);
    
    // 停止更新位置
    [self.locaationManager stopUpdatingLocation];
}

运行效果如下:
在这里插入图片描述
这样我们的位置信息就获取完成了,可能大家看到了,在这个位置信息获取完成之后为什么要写上一个停止更新位置呢?在此我就来解答依稀,一般来说苹果建议我们在获取完位置之后就停止定位,因为电量的消耗是非常大的,但如果我们需要,可以使用以下方法:
[self.locaationManager startMonitoringSignificantLocationChanges]
该方法可以说是一个重大变化通知,避免了随时定位的耗电,当设备检查到数据变化大,就主动调起didUpdateLocations方法来完成位置的改变。

CLLocation详细使用,定位数据处理

在上面我们看到了一个类:CLLocation。和CLLocationManager很像是吧?官方有话说:CLLocation对象包含设备的地理位置和高度,以及指示这些测量值的准确性和收集时间的值。在iOS中,位置对象还包含航向信息,即设备移动的速度和方向。

那我们如何来获得这些信息呢?上代码:

- (void)learningCLLocation{
    /**
     定位管理器返回的位置是用CLLoation实例表示的,里面包含了有关位置的重要信息
     比如:
     CLLocationCoordinate2D 用来表示经纬度坐标
     使用方式:
     CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude) 创建一个经纬度坐标
     coordinate.latitude,coordinate.longitude 读取经纬度
     
     CLLocationDistance  用来表示实际位置和返回坐标之间的距离(以米为单位)
     使用方式:获取
     location.altitude
     
     CLLocationAccuracy 地理坐标的准确性
     使用方式:获取
     location.horizontalAccuracy; 指定坐标的水平精度(以米为单位)
     location.verticalAccuracy; 高度值的精度(以米为单位)
     
     timestamp 时间戳,指出何时在定位管理器获取的位置
     使用方式:获取
     location.timestamp
     
     CLLocationSpeed 装置运动的速度(以米每秒为单位)
     使用方式:获取
     location.speed
     
     CLLocationDirection 方位角以相对于真北的角度来测量的方位角
     使用方式:获取
     location.course
     */
}

已经很详细的表达出来啦,这些数据可能会有用,希望大家能记下来。虽然我们已经获取了定位的数据,但这些数据我们确实看着不懂,那我们该怎么办呢?苹果提供了一个CLGeocoder类,这个类是用于在地理坐标和地名之间转换的接口,也就是常说的逆地理编码(反地理编码)

// 反地理编码(根据当前的经纬度获取具体的位置信息)
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        for (CLPlacemark *placeMark in placemarks) {
            NSLog(@"位置:%@", placeMark.name);
            NSLog(@"街道:%@", placeMark.thoroughfare);
            NSLog(@"子街道:%@", placeMark.subThoroughfare);
            NSLog(@"市:%@", placeMark.locality);
            NSLog(@"区\\县:%@", placeMark.subLocality);
            NSLog(@"行政区:%@", placeMark.administrativeArea);
            NSLog(@"国家:%@", placeMark.country);
        }
    }];

实现之后效果如下:
iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第2张图片
这样我们的当前定位数据就是很直观的展现出来啦。


GPX虚拟定位文件的使用以及模拟器定位使用

当我们没有真机调试或者需要进行简单的定位调试的时候,我们会使用GPX虚拟定位文件或者直接使用模拟器的定位工具,可能有的小伙伴不太懂,我这里就给大家讲一下:

  • GPX虚拟定位文件
    首先在工程中 cmd + n 打开文件创建页面,找到gpx文件,如图:iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第3张图片
    然后在选择运行设备的地方选择 Eidt Scheme,按照下图方式进行操作:

    然后就会在项目中发现我们的GPX虚拟定位文件啦,之后我们在该文件里面作出修改,运行项目,就可以获得目标位置的信息,修改文件内容如下图:
    iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第4张图片
    把lat和lng以及name修改就行,时间戳不用修改,这样我们的GPX虚拟定位文件就添加好并可以使用了,使用方式直接选择模拟器运行就可以。如果说GPX文件操作比较繁琐和复杂,我们还可以使用模拟器的工具来进行定位修改,如图:iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第5张图片
    iOS开发-用户定位获取-CoreLocation的实际应用-CLLocationManger获取定位权限-CLLocation详细使用方式_第6张图片
    然后输入目标经纬度就可以完成位置录入了。

补充说明:

之前面试的时候谈及耗电量优化,在新的API中,苹果提供了单次定位请求的功能,也就是获取一次位置信息,代码:

[self.locaationManager requestLocation]

其实现逻辑是按照定位精确度从低到高进行排序,逐个进行定位。如果在有效时间内,定位到了精确度最好的位置,那么就把对应的位置通过代理告知外界,如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉我们。需要注意的是:必须实现代理的locationManager:didFailWithError:方法,不能与startUpdatingLocation方法同时使用。
实现如下:

// 代理方法,错误处理
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    NSLog(@"%@",error);
    // 如果管理器未能获取位置,可能是GPS或者网络信号不可用等情况,这时候不要再继续消耗性能
    // 停止更新位置
    [self.locaationManager stopUpdatingLocation];
}

好了这期的内容到这里就结束了,下期就开讲原生的MapKit,到时候直接是可视化的地图定位信息,大家伙期待吗?~

下期内容:MapKit的实际应用

你可能感兴趣的:(iOS开发基础,iOS技术点开发)