CoreLocation框架地图定位(iOS9全适配)

1. 简介

在移动互联网时代,移动 app 能解决用户的很多生活琐事,比如
周边:找餐馆、 KTV 找电 影院等等
:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达
在上述应用中, 都用到了 定位 地图 能,在 iOS 开发中,要想加入这 2 大功能,必须基于 2 个框架进行开发
CoreLocation :用于 地理 定位,地理编码,区域监听等( 着重功能实现
MapKit :用于地图 展示,例如大头针,路线、覆盖层展示等( 着重界面展示
2 个热门专业术语
LBS Location Based Service
SoLoMo Social Local Mobile (索罗门)
2. 使用 CoreLocation 框架的使用

导入主头文件 #import < CoreLocation / CoreLocation.h >

CoreLocation 框架中所有数据类型的前缀都是 CL
CoreLocation 中使用 CLLocationManager 对象来做用户定位

2.1 CLLocationManager

开始更新用户位置
-( void)startUpdatingLocation;
停止更新用户位置
-( void)stopUpdatingLocation;

当调用了startUpdatingLocation 方法后,就开 始不断地请求、刷新用户 的位置 ,一旦请求到用户位置就会调 用代理的下面方法
-( void)locationManager:( CLLocationManager*)manager didUpdateLocations:( NSArray*)locations;
locations 参数里面装着 CLLocation 对象

为了严谨起见,最好在使用定位功能之前判断当前应用的定位功能是否可用
CLLocationManager 有个类方法可以判断当前应用的定位功能是否可用

  +(BOOL)locationServicesEnabled;


@ property( assign, nonatomic) CLLocationDistancedistanceFilter;   //每隔多少米定位一次
@property( assign, nonatomic) CLLocationAccuracydesiredAccuracy;   //定位精确度(越精确就越耗电)
2.2  CLLocation
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等
@property(readonly,nonatomic)CLLocationCoordinate2Dcoordinate;  // 经纬度

@property(readonly,nonatomic)CLLocationDistancealtitude;  // 海拔

@property(readonly,nonatomic)CLLocationDirectioncourse;  // 路线,航向(取值范围是 0 . ~ 359.9° 0.0° 代表真北方向)

@property(readonly,nonatomic)CLLocationSpeedspeed;  // 移动速度 (单位是 m/s

-(CLLocationDistance)distanceFromLocation:(constCLLocation p*)location 方法可以计算 2 个位置之间的距离





3. ios8.0-定位适配
iOS 6 始, 苹果在保护用户隐私方面做了很大的加强,以下操作都 必须经过用户批准授权
要想获得用户的位置、 想访问用户的通讯录、日历、相机、相册等等
当想访问用户的隐私信息时,系统会 自动 弹出一个对话框让用户授权

开发者可以在 Info.plist 中设置 NSLocationUsageDescription 说明定位的目的 (Privacy -Location Usage Description) 这种配置只适用于iOS8.0及以前的,iOS8.0以后的就不会再读了
在info.plist中点击加号,增加这样一个字段




效果:


iOS 8 .0 始, 苹果 进一步加强 了对用户隐私的保护。
APP 想访问用户 的隐私信息时, 系统 不再自动 弹出一个对话框让用户授权
解决方案:

  (1)调用iOS8.0的API主动请求用户授权

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

(2)务必在info.plist文件中配置对应的键值,否则以上请求授权的方法不生效

NSLocationAlwaysUsageDescription : 允许在前后台获取 GPS 的描述
NSLocationWhenInUseDescription   : 允许 在前台获取 GPS 的描述

开启后台定位:首先点击target然后按下图步骤


开启后台定位后再info.plist中就多了这个

#pragma mark - 懒加载
- (CLLocationManager *)lM
{
    if (!_lM) {
        // 1. 创建位置管理者
        _lM = [[CLLocationManager alloc] init];
        // 1.1 代理, 通知, block
        _lM.delegate = self;
        
        // 每隔多米定位一次 (1°≈111km)设置100米定位一次 可以点击模拟器 然后点击debug然后点击custom location 然后改变0.1就可以了
        _lM.distanceFilter = 100;
        
    }
    return _lM;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 2. 使用位置管理者,开始更新用户位置
    // 默认只能在前台获取用户位置,
    // 勾选后台模式 location updates
    [self.lM startUpdatingLocation];
}

#pragma mark - CLLocationManagerDelegate
/**
 *  更新到位置之后调用
 *
 *  @param manager   位置管理者
 *  @param locations 位置数组
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了");
    // 拿到位置,做一些业务逻辑操作
    // 停止更新
    [manager stopUpdatingLocation];
}
可以点击模拟器 然后点击debug然后点击custom location 然后改变0.1就可以了






定位精度:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>

/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *lM;

@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor];
    // Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - 懒加载
- (CLLocationManager *)lM
{
    if (!_lM) {
        // 1. 创建位置管理者
        _lM = [[CLLocationManager alloc] init];
        // 1.1 代理, 通知, block
        _lM.delegate = self;
        
        // 每隔多米定位一次 (1°≈111km)设置100米定位一次 可以点击模拟器 然后点击debug然后点击custom location 然后改变0.1就可以了
       // _lM.distanceFilter = 100;
        /**
           kCLLocationAccuracyBestForNavigation // 最适合导航
           kCLLocationAccuracyBest; // 最好的
           kCLLocationAccuracyNearestTenMeters; // 10m
           kCLLocationAccuracyHundredMeters; // 100m
           kCLLocationAccuracyKilometer; // 1000m
           kCLLocationAccuracyThreeKilometers; // 3000m
         */
        // 精确度越高, 越耗电, 定位时间越长
        _lM.desiredAccuracy = kCLLocationAccuracyBest;
    }
    return _lM;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 2. 使用位置管理者,开始更新用户位置
    // 默认只能在前台获取用户位置,
    // 勾选后台模式 location updates
    [self.lM startUpdatingLocation];
}

#pragma mark - CLLocationManagerDelegate
/**
 *  更新到位置之后调用
 *
 *  @param manager   位置管理者
 *  @param locations 位置数组
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了");
    // 拿到位置,做一些业务逻辑操作
    // 停止更新
    [manager stopUpdatingLocation];
}


4. iOS8.0+适配 

4.1 requestAlwaysAuthorization 方法 //前台定位授权(默认情况下,不可以在后台获取位置)

文档对这个方法的说明:(如果没有在info.plist中做相应的配置的话,这个方法是没有作用的)

/*

 *  requestWhenInUseAuthorization

 *

 *  Discussion:

 *      When +authorizationStatus == kCLAuthorizationStatusNotDetermined,

 *      calling this method will trigger a prompt to request "when-in-use"

 *      authorization from the user.  If possible, perform this call in response

 *      to direct user request for a location-based service so that the reason

 *      for the prompt will be clear.  Any authorization change as a result of

 *      the prompt will be reflected via the usual delegate callback:

 *      -locationManager:didChangeAuthorizationStatus:.

 *

 *      If received, "when-in-use" authorization grants access to the user's

 *      location via -startUpdatingLocation/-startRangingBeaconsInRegion while

 *      in the foreground.  If updates have been started when going to the

 *      background, then a status bar banner will be displayed to maintain

 *      visibility to the user, and updates will continue until stopped

 *      normally, or the app is killed by the user.

 *

 *      "When-in-use" authorization does NOT enable monitoring API on regions,

 *      significant location changes, or visits, and -startUpdatingLocation will

 *      not succeed if invoked from the background.

 *

 *      When +authorizationStatus != kCLAuthorizationStatusNotDetermined, (ie

 *      generally after the first call) this method will do nothing.

 *

 *      If the NSLocationWhenInUseUsageDescription key is not specified in your

 *      Info.plist, this method will do nothing, as your app will be assumed not

 *      to support WhenInUse authorization.

 */

- (void)requestAlwaysAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0) __TVOS_PROHIBITED;


拷贝  NSLocationAlwaysUsageDescription 在info.plist中配置


4.2  [_lM requestAlwaysAuthorization]  方法  // 当前的授权状态为前台授权时 , 此方法也会有效

/*
 *  requestAlwaysAuthorization
 *
 *  Discussion:
 *      When +authorizationStatus == kCLAuthorizationStatusNotDetermined,
 *      calling this method will trigger a prompt to request "always"
 *      authorization from the user.  If possible, perform this call in response
 *      to direct user request for a location-based service so that the reason
 *      for the prompt will be clear.  Any authorization change as a result of
 *      the prompt will be reflected via the usual delegate callback:
 *      -locationManager:didChangeAuthorizationStatus:.
 *
 *      If received, "always" authorization grants access to the user's
 *      location via any CLLocationManager API, and grants access to
 *      launch-capable monitoring API such as geofencing/region monitoring,
 *      significante location visits, etc.  Even if killed by the user, launch
 *      events triggered by monitored regions or visit patterns will cause a
 *      relaunch.
 *
 *      "Always" authorization presents a significant risk to user privacy, and
 *      as such requesting it is discouraged unless background launch behavior
 *      is genuinely required.  Do not call +requestAlwaysAuthorization unless
 *      you think users will thank you for doing so.
 *
 *      When +authorizationStatus != kCLAuthorizationStatusNotDetermined, (ie
 *      generally after the first call) this method will do nothing.
 *
 *      If the NSLocationAlwaysUsageDescription key is not specified in your
 *      Info.plist, this method will do nothing, as your app will be assumed not
 *      to support Always authorization.
 */
拷贝  NSLocationAlwaysUsageDescription
配置


            

 
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>

/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *lM;

@end

@implementation ViewController

#pragma mark - 懒加载
- (CLLocationManager *)lM
{
    if (!_lM) {
        // 1. 创建位置管理者
        _lM = [[CLLocationManager alloc] init];
        // 1.1 代理, 通知, block
        _lM.delegate = self;
        
        // 每隔多米定位一次
//        _lM.distanceFilter = 100;
        /**
           kCLLocationAccuracyBestForNavigation // 最适合导航
           kCLLocationAccuracyBest; // 最好的
           kCLLocationAccuracyNearestTenMeters; // 10m
           kCLLocationAccuracyHundredMeters; // 100m
           kCLLocationAccuracyKilometer; // 1000m
           kCLLocationAccuracyThreeKilometers; // 3000m
         */
        // 精确度越高, 越耗电, 定位时间越长
        _lM.desiredAccuracy = kCLLocationAccuracyBest;
        /** -------iOS8.0+定位适配-------- */
        
        if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
        {
            // 前台定位授权(默认情况下,不可以在后台获取位置, 勾选后台模式 location update, 但是 会出现蓝条)
//            [_lM requestWhenInUseAuthorization];
            // 前后台定位授权(请求永久授权)
            // +authorizationStatus != kCLAuthorizationStatusNotDetermined
            // 这个方法不会有效
            // 当前的授权状态为前台授权时,此方法也会有效
            [_lM requestAlwaysAuthorization];

        }
        
//        if ([_lM respondsToSelector:@selector(requestAlwaysAuthorization)])
//        {
//            [_lM requestAlwaysAuthorization];
//        }
        
    }
    return _lM;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 2. 使用位置管理者,开始更新用户位置
    // 默认只能在前台获取用户位置,
    // 勾选后台模式 location updates
    [self.lM startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
/**
 *  更新到位置之后调用
 *
 *  @param manager   位置管理者
 *  @param locations 位置数组
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了");
    // 拿到位置,做一些业务逻辑操作
    // 停止更新
//    [manager stopUpdatingLocation];
}

/**
 *  授权状态发生改变时调用
 *
 *  @param manager 位置管理者
 *  @param status  状态
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
            // 用户还未决定
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户还未决定");
            break;
        }
            // 问受限
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            break;
        }
            // 定位关闭时和对此APP授权为never时调用
        case kCLAuthorizationStatusDenied:
        {
            // 定位是否可用(是否支持定位或者定位是否开启)
            if([CLLocationManager locationServicesEnabled])
            {
                NSLog(@"定位开启,但被拒");
            }else
            {
                NSLog(@"定位关闭,不可用");
            }
//            NSLog(@"被拒");
            break;
        }
            // 获取前后台定位授权
        case kCLAuthorizationStatusAuthorizedAlways:
            //        case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
        {
            NSLog(@"获取前后台定位授权");
            break;
        }
            // 获得前台定位授权
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"获得前台定位授权");
            break;
        }
        default:
            break;
    }
}


@end

5.iOS9.0适配  allowsBackgroundLocationUpdates =YES;

/*
 *  allowsBackgroundLocationUpdates
 *
 *  Discussion:
 *      By default, this is NO for applications linked against iOS 9.0 or later,
 *      regardless of minimum deployment target.
 *
 *      With UIBackgroundModes set to include "location" in Info.plist, you must
 *      also set this property to YES at runtime whenever calling
 *      -startUpdatingLocation with the intent to continue in the background.
 *
 *      Setting this property to YES when UIBackgroundModes does not include
 *      "location" is a fatal error.
 *
 *      Resetting this property to NO is equivalent to omitting "location" from
 *      the UIBackgroundModes value.  Access to location is still permitted
 *      whenever the application is running (ie not suspended), and has
 *      sufficient authorization (ie it has WhenInUse authorization and is in
 *      use, or it has Always authorization).  However, the app will still be
 *      subject to the usual task suspension rules.
 *
 *      See -requestWhenInUseAuthorization and -requestAlwaysAuthorization for
 *      more details on possible authorization values.
 */
代码:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>

/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *lM;

@end

@implementation ViewController

#pragma mark - 懒加载
- (CLLocationManager *)lM
{
    if (!_lM) {
        // 1. 创建位置管理者
        _lM = [[CLLocationManager alloc] init];
        // 1.1 代理, 通知, block
        _lM.delegate = self;
        
        // 每隔多米定位一次
//        _lM.distanceFilter = 100;
        /**
           kCLLocationAccuracyBestForNavigation // 最适合导航
           kCLLocationAccuracyBest; // 最好的
           kCLLocationAccuracyNearestTenMeters; // 10m
           kCLLocationAccuracyHundredMeters; // 100m
           kCLLocationAccuracyKilometer; // 1000m
           kCLLocationAccuracyThreeKilometers; // 3000m
         */
        // 精确度越高, 越耗电, 定位时间越长
        _lM.desiredAccuracy = kCLLocationAccuracyBest;
        
        
        /** -------iOS8.0+定位适配-------- */
        
        if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
        {
            // 前台定位授权(默认情况下,不可以在后台获取位置, 勾选后台模式 location update, 但是 会出现蓝条)
            [_lM requestWhenInUseAuthorization];
            
            
            // 前后台定位授权(请求永久授权)
            // +authorizationStatus != kCLAuthorizationStatusNotDetermined
            // 这个方法不会有效
            // 当前的授权状态为前台授权时,此方法也会有效
            [_lM requestAlwaysAuthorization];

        }
        // 允许后台获取用户位置(iOS9.0)
         if([[UIDevice currentDevice].systemVersion floatValue] >= 9.0)
         {
             // 一定要勾选后台模式 location updates
             _lM.allowsBackgroundLocationUpdates = YES;
         }
        
//        if ([_lM respondsToSelector:@selector(requestAlwaysAuthorization)])
//        {
//            [_lM requestAlwaysAuthorization];
//        }
        
    }
    return _lM;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    // 2. 使用位置管理者,开始更新用户位置
    // 默认只能在前台获取用户位置,
    // 勾选后台模式 location updates
    [self.lM startUpdatingLocation];
    
    
    /**
     kCLLocationAccuracyBestForNavigation // 最适合导航
     kCLLocationAccuracyBest; // 最好的
     kCLLocationAccuracyNearestTenMeters; // 10m
     kCLLocationAccuracyHundredMeters; // 100m
     kCLLocationAccuracyKilometer; // 1000m
     kCLLocationAccuracyThreeKilometers; // 3000m
     */
    
//    [self.lM requestLocation];
}

#pragma mark - CLLocationManagerDelegate
/**
 *  更新到位置之后调用
 *
 *  @param manager   位置管理者
 *  @param locations 位置数组
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了");
    
    // 拿到位置,做一些业务逻辑操作
    
    
    // 停止更新
//    [manager stopUpdatingLocation];
    
    
    
}

/**
 *  授权状态发生改变时调用
 *
 *  @param manager 位置管理者
 *  @param status  状态
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
            // 用户还未决定
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户还未决定");
            break;
        }
            // 问受限
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            break;
        }
            // 定位关闭时和对此APP授权为never时调用
        case kCLAuthorizationStatusDenied:
        {
            // 定位是否可用(是否支持定位或者定位是否开启)
            if([CLLocationManager locationServicesEnabled])
            {
                NSLog(@"定位开启,但被拒");
            }else
            {
                NSLog(@"定位关闭,不可用");
            }
//            NSLog(@"被拒");
            break;
        }
            // 获取前后台定位授权
        case kCLAuthorizationStatusAuthorizedAlways:
            //        case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
        {
            NSLog(@"获取前后台定位授权");
            break;
        }
            // 获得前台定位授权
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"获得前台定位授权");
            break;
        }
        default:
            break;
    }

    
    
}

// 定位失败
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"定位失败");
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值