您的位置:首页 > 移动开发 > IOS开发

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

2016-03-18 10:42 489 查看
1. 简介

在移动互联网时代,移动app能解决用户的很多生活琐事,比如
周边:找餐馆、找KTV、找电影院等等
导航:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达
在上述应用中,都用到了定位和地图功能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发
CoreLocation :用于地理定位,地理编码,区域监听等(着重功能实现)
MapKit:用于地图展示,例如大头针,路线、覆盖层展示等(着重界面展示)
2个热门专业术语
LBS :LocationBasedService
SoLoMo :SocialLocalMobile(索罗门)
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.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(@"定位失败");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: