简介:
在移动互联网时代,移动app能解决用户的很多生活琐事,比如周边:找餐馆、找KTV、找电影院等等
导航:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达。
在上述应用中,都用到了定位和地图功能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发:
CoreLocation:用于地理定位,如:地理编码,区域监听等(着重功能实现)
MapKit:用于地图展示,例如大头针,路线、覆盖层展示等(着重界面展示)
2个专业术语:
LBS:location Based Service (基于位置的服务)
ScLoMo:Social Local Mobile (索罗门)
定位
CoreLocation:用于地理定位,地理编码,区域监听等(着重功能实现)
地理编码:将某个位置转换为经纬度,如:北京天安门->100.333445 , 22.88888
反地理编码:将某个位置的经纬度转换为文字描述的具体位置,如:100.333445 , 22.88888 ->北京天安门
区域监听:监听某个位置是否在某个区域。
CoreLocation的使用
第一种方式:
导入框架 :CoreLocation.frameWork
导入头文件:#import<CoreLocation/CoreLocation.h>
第二种方式:
只需导入头文件即可,前提是代码中使用CoreLocation框架中的某一个类创建的对象,他就会在链接的过程中隐式的把对应的框架链接进来。
经验:CoreLocation框架中所有的类型数据的前缀都是以CL开头。
CoreLocation框架中使用CLLocationManager对象来做定位服务。
iOS8.0之前的定位实现:
1、创建位置管理者:
_manager = [[CLLocationManager alloc] init];
2、设置代理:通过代理来获取位置信息等,遵守代理协议。
_manager.delegate = self;
3、开始定位:startUpdatingLocation调用此方法开始定位,会不断的获取用户的位置信息
[self.manager startUpdatingLocation];
4、实现代理方法:获取用户的位置信息等。
*只要获取到用户的位置的时候就会调用(很频繁)
* @param manager位置管理者
* @param locations位置数组 ,位置信息等,都在数字的最后一个元素
- (void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"%@",locations);
CLLocation*location = [locationslastObject];
}
到此定位完成。
运行会弹出如图:
PS:从iOS6开始,苹果在保护用户隐私方面做了很大的加强,只要是要想获得用户的位置、想访问用户的通讯录、日历、相机、相册等操作,都必须经过用户批准授权,开发者可以在Info.plist中设置NSLocationUsageDescription说明定位的目的.
如何判断授权状态?
通过代理方法didChangeAuthorizationStatus:
*当授权状态发生改变时调用
* @param manager位置管理者
* @param status当前授权状态 有五种状态
- (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch(status) {
case kCLAuthorizationStatusNotDetermined:
NSLog(@"用户未决定");
break;
case kCLAuthorizationStatusRestricted:
NSLog(@"受限制");
break;
case kCLAuthorizationStatusDenied:
//判断当前设备是否支持定位,并且定位是否开启
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但是被拒绝");
// ios8.0之前需要截图提醒引导用户,如何接受授权。
// iOS8.0之后只需要调用系统只带的API就会自动跳转到设置界面。
}else{
NSLog(@"定位未开启");
}
break;
case kCLAuthorizationStatusAuthorizedAlways:
NSLog(@"前后台");
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
NSLog(@"前台");
break;
default:
break;
}
}
其他属性设置
- (void)stopUpdatingLocation :停止定位(针对一次性定位,比如定位到用户位置之后就停止),可以在上面的代理方法中使用。
distanceFilter:每隔多远定位一次,比如:_manager.distanceFilter=10;代表每隔10米定位一次。
desiredAccuracy:定位的精确度(越精确,越耗电)。它的取值比较多有6种,如下
kCLLocationAccuracyBestForNavigation //最适合导航
kCLLocationAccuracyBest; //最好的
kCLLocationAccuracyNearestTenMeters;//附近10米
kCLLocationAccuracyHundredMeters;//附近100米
kCLLocationAccuracyKilometer;//附近1000米
kCLLocationAccuracyThreeKilometers;//附近3000米
- (CLLocationDistance)distanceFromLocation:(constCLLocation*)location方法可以计算2个位置之间的距离
coordinate:经纬度
altitude:海拔
course:路线,航向(取值范围是0.0°~359.9°,0.0°代表真北方向)
speed:移动速度(单位是m/s)
horizontalAccuracy如果是负数,代表当前位置不可用
PS:目前的定位只是前台定位,APP进入后台就不再定位,如果要实现前后台定位的话,必须手动设置后台模式。如图
iOS8.0之后的定位实现
把以上代码再跑到iOS8.0+的时候,并没有弹出授权提示框,这是因为从iOS8.0开始,苹果进一步加强了对用户隐私的保护,当APP想访问用户的隐私信息时,系统不再自动弹出一个对话框让用户授权。
解决方案:调用iOS8.0的API,主动请求用户授权
- (void)requestAlwaysAuthorization//请求允许在前后台都能获取用户位置的授权
- (void)requestWhenInUseAuthorization//请求允许在前台获取用户位置的授权
以上二选一。
务必在info.plist文件中配置对应的键值,否则以上请求授权的方法不生效
NSLocationAlwaysUsageDescription:允许在前后台获取GPS的描述
NSLocationWhenInUseDescription:允许在前台获取GPS的描述
以上二选一,和上面的调用方法要保持一直。
if([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
[_managerrequestAlwaysAuthorization];
}
iOS9.0之后的定位实现
iOS9.0如果当前处于前台授权状态,默认是不可以后台获取用户位置。但可以设置以下属性为YES,就可以继续获取后台位置,但是会出现蓝条;
if([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
[_managerrequestAlwaysAuthorization];
if([UIDevicecurrentDevice].systemVersion.floatValue>=9.0)
{
_manager.allowsBackgroundLocationUpdates=YES;
}
}
PS:iOS9.0可以单次请求用户位置
- (void)requestLocation注意:此方法不能与startUpdatingLocation一起使用。
-(void)locationManager:(nonnullCLLocationManager*)managerdidUpdateLocations:(nonnullNSArray *)locations//成功调用
-(void)locationManager:(nonnullCLLocationManager*)managerdidFailWithError:(nonnullNSError*)error//失败调用
地理编码:CLGeocoder
使用CLGeocoder可以完成“地理编码”和“反地理编码”。
地理编码方法
- (void)geocodeAddressString:(NSString*)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理编码方法
- (void)reverseGeocodeLocation:(CLLocation*)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
CLGeocodeCompletionHandler
当地理\反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedefvoid(^CLGeocodeCompletionHandler)(NSArray*placemarks,NSError*error);
这个block传递2个参数
error:当编码出错时(比如编码不出具体的信息)有值
placemarks:里面装着CLPlacemark对象
CLPlacemark
CLPlacemark的字面意思是地标,封装详细的地址位置信息
@property(nonatomic,readonly)CLLocation*location;
地理位置
@property(nonatomic,readonly)CLRegion*region;
区域
@property(nonatomic,readonly)NSDictionary*addressDictionary;
详细的地址信息
@property(nonatomic,readonly)NSString*name;
地址名称
@property(nonatomic,readonly)NSString*locality;
城市
地理编码案例:输入经纬度,点击地理编码按钮,可得到详细地址;输入详细地址,点击反地理编码按钮,可得到相应的经纬度。如图:
首先在storyboard布局好界面,连好线。
code:
案例:封装简单定位工具类(代理模式转block模式),获取用户位置,通过blcok回调返回用户位置信息。
一、创建单例工具类
YWZLocationTools.h
YWZLocationTools.m
YWZLocationTools.h中的代码
YWZLocationTools.m中的代码
在ViewController里使用工具类