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

来源:互联网 发布:梦里花落知多少顾小北 编辑:程序博客网 时间:2024/05/29 10:31

1. 简介

在移动互联网时代,移动app能解决用户的很多生活琐事,比如
周边:找餐馆、KTV找电影院等等
:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达
在上述应用中,都用到了定位地图能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发
CoreLocation :用于地理定位,地理编码,区域监听等(着重功能实现
MapKit:用于地图展示,例如大头针,路线、覆盖层展示等(着重界面展示
2个热门专业术语
LBSLocationBasedService
SoLoMoSocialLocalMobile(索罗门)
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:(constCLLocationp*)location方法可以计算2个位置之间的距离





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

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




效果:


iOS8.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
原创粉丝点击