美文网首页iOS 地图
IOS地图定位导航

IOS地图定位导航

作者: 袁俊亮技术博客 | 来源:发表于2016-04-18 16:54 被阅读1073次

    title : IOS地图定位导航
    category : UI


    地图定位导航

    标签(空格分隔): IOS


    概述

    IOS中通过CoreLocation框架进行定位操作

    在IOS开发中,定位地图两个功能是基于CoreLocationMapKit这两个框架来开发

    • CoreLocation:用于地理定位,地理编码,区域监听等(着重功能实现)

    • MapKit:用于地图展示,例如大头针,路线,覆盖层展示等(着重界面展示)

    • 两个热门专业术语

      • LBS:Location Based Service
      • SoLoMo:Social Local Mobile(索罗门):社交化、本地化、移动化

    CoreLocation框架的使用

    • CoreLocation自身可以单独使用,和MapKit框架是完全独立的两个框架,但实际开发中需要将他们两者结合起来使用
    • CoreLocation可以实现定位功能和地理编码与逆地理编码功能

    CLLocationManager的常用操作

    // 开始更新用户位置
    - (void)startUpdatingLocation;
    
    // 停止更新用户位置
    - (void)stopUpdatingLocation;
    
    // 当调用了startUpdatingLocation方法后,就开始不断地请求、刷新用户的位置,一旦请求到用户位置就会调用代理的以下方法
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations;
    

    1 类方法

    + (BOOL)locationServicesEnabled;/* 返回用户是否启用定位服务 */
    + (CLAuthorizationStatus)authorizationStatus;/* 定位服务授权状态,返回枚举类型 */
    
    typedef NS_ENUM(int, CLAuthorizationStatus){
        kCLAuthorizationStatusNotDetermined = 0, /* 用户尚未决定是否启用定位服务 */
        kCLAuthorizationStatusRestricted, /* 没有获得用户授权 */
        kCLAuthorizationStatusDenied, /* 用户禁止使用定位或者定位服务处于关闭状态 */
        kCLAuthorizationStatusAuthorizedAlways, /* 前台、后台定位授权 */
        kCLAuthorizationStatusAuthorizedWhenInUse, /* 前台定位授权 */
    };
    

    2 对象属性

    // 每隔多少米定位一次
    locationMgr.distanceFilter = 100;
    
    // 定位的精确度
    locationMgr.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    

    精确度枚举值(越精确就越耗电)

     kCLLocationAccuracyBestForNavigation /* 最适合导航的 */
     kCLLocationAccuracyBest; /* 精度最好的 */
     kCLLocationAccuracyNearestTenMeters; /* 附近10米 */
     kCLLocationAccuracyHundredMeters; /* 附近100米 */
     kCLLocationAccuracyKilometer; /* 附近1000米 */
     kCLLocationAccuracyThreeKilometers; /* 附近3000米 */
    

    3 对象方法

    #pragma mark - 定位追踪
    -(void)startUpdatingLocation;/* 开始定位追踪 */
    -(void)stopUpdatingLocation;/* 停止定位追踪 */
    #pragma mark - 导航追踪
    -(void)startUpdatingHeading;/* 开始导航方向追踪 */
    -(void)stopUpdatingHeading;/* 停止导航方向追踪 */
    #pragma mark - 区域定位追踪
    -(void)startMonitoringForRegion:(CLRegion *)region;/* 开始对某个区域进行定位追踪 */
    -(void)stopMonitoringForRegion:(CLRegion *)region;/* 停止对某个区域进行定位追踪 */
    #pragma mark - 授权请求
    -(void)requestWhenInUseAuthorization;/* 请求获得应用前台定位授权 */
    -(void)requestAlwaysAuthorization;/* 请求获得应用前后台定位授权 */
    

    4. 常用代理方法<CLLocationManagerDelegate>

    /* 位置发生改变后调用,第一次定位也会调用 */
    -(void)locationManager:(CLLocationManager *)manager 
        didUpdateLocations:(NSArray *)locations;
    /* 导航方向发生变化后调用 */
    -(void)locationManager:(CLLocationManager *)manager 
          didUpdateHeading:(CLHeading *)newHeading;
    /* 进入某个区域后调用 */
    -(void)locationManager:(CLLocationManager *)manager 
            didEnterRegion:(CLRegion *)region;
    /* 走出某个区域后调用 */
    -(void)locationManager:(CLLocationManager *)manager 
             didExitRegion:(CLRegion *)region;
    /* 当用户授权状态发生变化时调用 */
    -(void)locationManager:(CLLocationManager *)manager 
           didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
    

    CoreLocation定位功能的使用步骤

    • 首先导入头文件
    #import <CoreLocation/CoreLocation.h>
    

    IOS8.0之前的定位使用

    1.1 前台定位
    - (void)viewDidLoad{
        [super viewDidLoad];
        if (![CLLocationManager locationServicesEnabled]) {
            NSLog(@"定位服务当前可能尚未打开,请设置打开!");
            return;
        }
        [self initLocationManager];
        //调用方法,开始更新用户位置信息
        [self.locationM startUpdatingLocation];
    }
    //创建CLLocationManager并启动定位
    - (void)initLocationManager{
        //创建CLLocationManager对象并设置代理
        self.locationM = [[CLLocationManager alloc] init];
        self.locationM.delegate = self;
        //设置定位精度和位置更新最小距离
        self.locationM.distanceFilter = 100;
        self.locationM.desiredAccuracy = kCLLocationAccuracyBest;
    }
    //在对应的代理方法中获取位置信息
    - (void)locationManager:(CLLocationManager *)manager 
         didUpdateLocations:(NSArray<CLLocation*> *)locations
    {
        CLLocation *location = [locations firstObject];//取出第一个位置
        /* 
            使用位置前, 务必判断当前获取的位置是否有效
            如果水平精确度小于零, 代表虽然可以获取位置对象, 但是数据错误, 不可用
         */
        if (location.horizontalAccuracy < 0)
            return;
        CLLocationCoordinate2D coordinate = location.coordinate;//位置坐标 
        CGFloat longitude = coordinate.longitude;//经度
        CGFloat latitude = coordinate.latitude;//纬度
        CGFloat altitude = location.altitude;//海拔
        CGFloat course = location.course;//方向
        CGFloat speed = location.speed;//速度
        NSLog(@"经度:%f,纬度:%f",longitude,latitude);   
        NSLog(@"海拔:%f,方向:%f,速度:%f",altitude,course,speed);
        //如果不需要实时定位,使用完即使关闭定位服务
        [self.locationM stopUpdatingLocation];   
    }
    
    • 1 定位频率和定位精度并不是越精确越好,需要视实际情况而定,因为越精确越耗性能,也就越费电。
    • 2 定位成功后会根据设置情况频繁调用locationManager:didUpdateLocations:方法
    • 3 每个元素一个CLLocation代表地理位置信息,之所以返回数组是因为有些时候一个位置点可能包含多个位置。
    • 4 使用完定位服务后,如果不需要实时监控应该立即关闭定位服务,以节省资源。
    • 5 除了提供定位功能,还可以调用startMonitoringForRegion:方法对指定区域进行监控。
    1.2 后台定位

    在前台的基础上,在项目的Capabilities中的Background Modes打开,并勾选上Location updates。这样就可以开启后台定位模式了

    开启后台定位模式.png

    2 IOS8.0之后

    IOS8.0开始,苹果进一步加强了对用户隐私的保护。当APP想访问用户的隐私信息是,系统不再自动弹出一个对话框让用户授权

    解决方案:

    调用IOS8.0的API,主动请求用户授权

    // 请求允许在前后台都能获取用户位置的授权
    - (void)requestAlwaysAuthorization;
    
    // 请求允许在前台获取用户位置的授权
    - (void)requestWhenInUseAuthorization;
    

    注意务必需要在Info.plist文件中配置以下对应的键值,否则以上请求授权的方法不会生效。

    • (1)始终允许访问位置信息
    NSLocationAlwaysUsageDescription
    
    • (2)使用应用程序期间允许访问位置数据
    NSLocationWhenInUseUsageDescription
    
    - (void)viewDidLoad{
        [super viewDidLoad];
        if (![CLLocationManager locationServicesEnabled]) {
            NSLog(@"定位服务当前可能尚未打开,请设置打开!");
            return;
        }
        [self initLocationManager];
        //如果没有授权,则请求用户授权
        CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
        if (status == kCLAuthorizationStatusNotDetermined){
            //请求前台定位授权
            //[self.locationM requestWhenInUseAuthorization];
            //请求前后台定位授权
            [self.locationM requestAlwaysAuthorization];
        }
    }
    
    //创建CLLocationManager并启动定位
    - (void)initLocationManager{
        //创建CLLocationManager对象并设置代理
        self.locationM = [[CLLocationManager alloc] init];
        self.locationM.delegate = self;
        //设置定位精度和位置更新最小距离
        self.locationM.distanceFilter = 100;
        self.locationM.desiredAccuracy = kCLLocationAccuracyBest;
    }
    // 当用户授权状态发生变化时调用
    - (void)locationManager:(CLLocationManager *)manager 
            didChangeAuthorizationStatus:(CLAuthorizationStatus)status
    {
        switch (status) {
            case kCLAuthorizationStatusNotDetermined://用户还未决定
            {
                NSLog(@"用户还未决定");
                break;
            }
            case kCLAuthorizationStatusRestricted://访问受限
            {
                NSLog(@"访问受限");
                break;
            }
            case kCLAuthorizationStatusDenied://定位关闭时或用户APP授权为永不授权时调用
            {
                NSLog(@"定位关闭或者用户未授权");
                if ([CLLocationManager locationServicesEnabled]) {
        NSLog(@"定位开启,但被拒");
    }else{
        NSLog(@"定位关闭,不可用");
    }
                break;
            }
            case kCLAuthorizationStatusAuthorizedAlways://获取前后台定位授权
            {
                NSLog(@"获取前后台定位授权");
                [self.locationM startUpdatingLocation];
                break;
            }
            case kCLAuthorizationStatusAuthorizedWhenInUse://获得前台定位授权
            {
                NSLog(@"获得前台定位授权");
                [self.locationM startUpdatingLocation];
                break;
            }
            default:break;
        }
    }
    //在对应的代理方法中获取位置信息
    - (void)locationManager:(CLLocationManager *)manager 
         didUpdateLocations:(NSArray<CLLocation*> *)locations
    {
        CLLocation *location = [locations firstObject];//取出第一个位置
        /* 
            使用位置前, 务必判断当前获取的位置是否有效
            如果水平精确度小于零, 代表虽然可以获取位置对象, 但是数据错误, 不可用
         */
        if (location.horizontalAccuracy < 0)
            return;
        CLLocationCoordinate2D coordinate = location.coordinate;//位置坐标
        CGFloat longitude = coordinate.longitude;//经度
        CGFloat latitude = coordinate.latitude;//纬度
        CGFloat altitude = location.altitude;//海拔
        CGFloat course = location.course;//方向
        CGFloat speed = location.speed;//速度
        NSLog(@"经度:%f,纬度:%f",longitude,latitude);
        NSLog(@"海拔:%f,方向:%f,速度:%f",altitude,course,speed);
        //如果不需要实时定位,使用完即使关闭定位服务
        [self.locationM stopUpdatingLocation];
    }
    

    注意对于IOS8.0以后的提示请求访问用户地理位置的提示需要进行系统适配

    • 适配方式一
    // 系统适配
    if ([self.locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationMgr requestAlwaysAuthorization];
    }
    
    
    • 适配方式二:
    if ([[UIDevice currentDevice].systemVersion doubleValue]>8.0) {
        // 设置前后台授权定位
        [self.locationMgr requestAlwaysAuthorization];
        // 设置前台授权
        [self.locationMgr requestWhenInUseAuthorization];
    }
    
    
    • 对于IOS9.0如果只是开启前台定位,需要手动提示开启后台定位
    if ([self.locationMgr respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
        // 在IOS9.0以后,需要允许后台获取用户位置
        // 注意,这里同时需要勾选后台模式
        self.locationMgr.allowsBackgroundLocationUpdates = YES;
    }
    
    

    参考资料:
    iOS8中使用CoreLocation定位

    相关文章

      网友评论

      本文标题:IOS地图定位导航

      本文链接:https://www.haomeiwen.com/subject/ndqalttx.html