• CoreLocation框架的使用


    CoreLocation框架使用

    一.地图和定位的简介

    1.应用场景

    • 周边:找餐馆/找KTV/找电影院(团购APP)
    • 导航:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达(地图APP)

    2.iOS中加入定位和地图功能所依赖的框架

    • CoreLocation
      • 地理定位:定位用户所在的位置,获取对应的经纬度或者海拔等信息
      • 地理编码:具体位置->经纬度坐标
      • 反地理编码:经纬度坐标->具体位置
      • 区域监听:事先在APP内部通过代码,指定一个区域,当用户进入或离开区域的时候,都可以监听到
    • MapKit
      • 地图展示:展示一个地图给用户看,而且也可以在地图上添加一些大头针/路线/覆盖层等
      • 路线规划:给定两个位置信息,可以获取到两个点之间的导航数据(行走路线/行走步骤/行走时间等)

    3.两个热门专业术语

    • LBS(Location Based Service):基于位置的服务
    • SoLoMo(Social Local Mobile):索罗门
      • 社交化:在APP里面假如一些社交元素
      • 本地化:基于LBS的周边搜索,周边签到等服务
      • 移动化:移动网(3G/4G网,相对于有线/无线电脑网络),移动APP(相对于桌面应用)

    4.使用CoreLocation框架进行定位

    • 导入框架(Xcode5.0之后可以省略)
    • 导入主头文件 #import <CoreLocation/CoreLocation.h>
    • 使用CLLocationManager对象来做很多相关的位置服务

    二.iOS8.0之前的定位(了解)

    1.为什么了解

    • iOS8之前的版本慢慢即将被淘汰,不再做适配
    • 只要iOS8以后的定位功能实现,那么直接把代码跑到iOS8之前的设备上,依然是可以运行得,不需要做任何修改
    • 因为系统版本和Xcode版本原因,暂时没法安装iOS8之前的模拟器进行安装

    2.iOS8.0之前的前台定位

    • 导入CoreLocation框架及对应的主头文件
      • #import <CoreLocation/CoreLocation.h>
    • 创建CLLocationManager对象并设置代理
      • self.locationM = [[CLLocationManager alloc] init];
      • self.lacationM.delegate = self;
    • 调用方法,开始更新用户位置信息
      • [self.locationM startUpdatingLocation];
    • 在对应的代理方法中获取位置信息
      • locationManager:didUpdataLocations
    • 可以在info.plist文件中,配置Privacy - Location Usage Description来说明定位目的

    3.iOS8.0之前的后台定位

    • 后台定位:
      • 在前台定位的基础上
      • 勾选后台模式(Background Modes) - location updates
      • 或者直接设置info.plist文件,Required background modes -> App register for location updates
    • 测试环境:
      • Xcode7.0之前版本,例如Xcode6.4版本
      • 模拟器选择iOS8.0之前的版本
    • 常见问题:定位不到,对应的代理方法不执行
      1. 检查运行的模拟器是否是iOS8.0之前的系统版本
      2. 检查模拟器是否设置位置数据
      3. 确保代码无问题(一般都是代理没有设置,或者位置管理器对象是局部变量)
      4. 可能是模拟器bug,将模拟器位置设为none,然后再次设置数据,或者,重置模拟器

    三.iOS8.0之后的定位

    1.iOS8.0之后的前台定位

    • 前台定位
    • 在iOS8.0之前定位的代码基础上
    • 主动请求前台定位授权,并在info.plist文件中配置对应的key
      • [self.locationM requestWhenInUseAuthorization];
      • KEY: NSLocationWhenInUseUsageDescription
    • 注意
      • 不要忘记做版本适配
      • 不要忘记在info.plist中配置对应的key,千万注意key不要出现空格,很难检查
    • 测试环境
      • Xcode版本无要求
      • 模拟器选择iOS8.0之后(包含iOS8.0)

    2.iOS8.0之后的后台定位-方案1

    • 在前台定位的基础上,勾选后台模式location updates
    • 效果:当APP退到后台,会出现一个蓝条,不断提醒用户

    3.iOS8.0之后的后台定位-方案2

    • 在定位时,直接请求前后台定位授权,并在info.plist中配置对应的key
      • [self.locationM requestAlwaysAuthorization];
      • KEY:NSLocationAlwaysUsageDescription
    • 效果:无论是否勾选后台模式,都可以获取位置信息,而且无论前后台,都不会出现蓝条
    • 注意:
      • 不要忘记做版本适配
      • 不要忘记在info.plist中配置对应的key,千万注意key不要出现空格,很难检查
    • 测试环境
      • Xcode版本无要求
      • 模拟器选择iOS8.0之后,iOS9.0之前的版本

    四.iOS9.0之后的定位

    1.iOS9.0之后的定位

    • 定位变化
      • 前台定位:和iOS8.0之后一致,没有变化
      • 后台定位方案一:
        • 在前台定位授权的基础上,如果勾选了后台模式location updates之后,还需要额外设置属性allowBackgroundLocationUpdates = YES;
      • 后台定位方案二:
        • 直接请求前后台定位授权的情况,和iOS8.0之后一致,没有变化
    • 测试环境
      • Xcode7.0之后的版本
      • 模拟器选择iOS9.0之后的版本

    五.定位的补充

    1.监听用户授权状态

    • 实现位置管理者CLLocationManager代理方法
      • locationManager:didChangeAuthorizationStatus:
    • 各个授权状态对应的含义
      • kCLAuthorizationStatusNotDetermined:用户未决定
      • kCLAuthorizationStatusRestricted:定位服务访问受限(系统预留字段)
      • kCLAuthorizationStatusDenied:定位被拒绝
      • kCLAuthorizationStatusAuthorizedAlways:前后台定位授权
      • kCLAuthorizationStatusAuthorizedWhenInUse:前台定位授权
    • 开发经验
      • 如果进入到被拒绝的分支,应该判断是关闭了定位服务,还是真正被拒绝,需要根据不同的情况,给用户提示做出不同的选择
      • 直接跳转到"授权界面"的方法
        • URL:prefs:root=LOCATION_SERVICES
        • UIApplicationOpenSettingURLString(iOS8.0之后)

    2.额外参数设置

    • 额外设置
      • 每隔多少米定位一次:distanceFilter
      • 设置定位精确度:desiredAccuracy
        • kCLLocationAccuracyBestForNavigation:最适合导航
        • kCLLocationAccuracyBest:精度最好的
        • kCLLocationAccuracyNearestTenMeters:附近10米
        • kCLLocationAccuracyHundredMeters:附近100米
        • kCLLocationAccuracyKilometer:附近1000米
        • kCLLocationAccuracyThreeKilometers:附近3000米
    • 开发经验
      • 定位本身就非常耗电,定位的精确度越高,越耗电,定位时间越长
      • 为了省电,尽量在满足需求的情况下降低精确度

    3.知识补充

    • 标准定位服务
      • 定位实现方案:基于GPS/蓝牙/基站/WiFi定位,具体使用哪种,苹果有自己的规则
      • 优点:定位精度高
      • 缺点:程序关闭,就没法获取位置,而且耗电
    • 显著位置变化定位服务
      • 定位实现方案:基于基站定位,必须要求设备有电话模块
      • 优点:当app被完全关闭时,也可以接收到位置通知,并让app进入到后台处理
      • 缺点:定位精度低
    • 应用场景:
      • 如果要求定位及时,精度较高,并且运行时间较短,可使用标准定位
      • 如果长时间监控用户位置,用户移动速度比较快(比如,打车软件),可使用后者
    • 新的API
      • 单次定位请求
        • 代码:[self.locationM requestLocation];
        • 功能:获取一次位置信息
      • 实现逻辑:
        • 按照定位精确度从低到高进行排序,逐个进行定位.如果在有效时间内,定位到了精确度最好的位置,那么就把对应的位置通过代理告知外界.
        • 如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界
      • 注意事项:
        • 必须实现代理的locationManager:didFailWithError:方法
        • 不能与startUpdatingLocation方法同时使用
      • 常见问题:
        • 单次定位在模拟器上测试不出效果?
          • 答:因为模拟器的位置是固定的,所以无法测试出下效果,需要使用真机进行测试.
        • 单次定位,控制台打印多次位置信息
          • 答:因为模拟器bug,需要以真机测试为准,亲测,只打印一次.

    六.CLLocation对象

    1.CLLocation对象详解

    • 属性解释
      • coordinate:当前位置所在的经纬度数据
      • altitude:海拔
      • speed:当前速度
      • course:航向(设备的移动方向,值域范围0.0~359.9,正北方向为0.0)
    • 重要方法
      • distanceFromLocation:location
      • 作用:计算两个位置对象之间的物理距离,单位是米
    • 开发经验
      • 使用之前,务必判断数据是否有效
      • 代码:if(location.horizontalAccuracy<0) return;
      • 功能:如果水平精度小于0,带包虽然可以获取位置对象,但是数据错误,不可用

    2.CLLocation场景演练

    七.定位的经验小结

    1.定位的应用场景

    • 导航
    • 电商APP,获取用户所在的城市(需要与地理编码/反地理编码联合使用)
    • 数据采集用户信息(例如,统计app使用分布)
    • 查找周边(周边好友,周边商家等等)

    2.开发经验

    • 由于定位非常耗电,所以为了给用户省电,有如下经验:
    • 不需要获取用户位置时,一定要关闭定位服务
    • 如果可以,尽可能使用低精度的desiredAccuracy
    • 如果是数据采集(一般都是周期性的去轮询用户位置),在轮询期一定要关闭定位

    八.指南针效果的实现

    1.实现思路

    • 利用"磁力计"传感器,获取设备朝向
    • 根据设备朝向,反向旋转"指南针"图片

    2.代码实现

    • 获取设备朝向
      • 导入CoreLocation框架及对应的主头文件
      • 创建CLLocationManager对象并设置代理
      • 调用[self.locationM startUpdatingHeading]方法,开始获取设备朝向
      • 在对应的代理方法中获取设备朝向信息
        • locationManager:didUpdateHeading
    • 旋转图片
      • 判断当前的角度(newHeading.headingAccuracy)是否有效(如果此值小于0,代表角度无效)
      • 获取当前设备朝向(磁北方向)
        • CGFloat angle = newHeading.magneticHeading;
      • 转换成弧度
        • CGFloat radian = angle / 180.0 * M_PI;
      • 带动画反向旋转指南针
        • self.compassView.transform = CGAffineTransformMakeRotation(-radian);

    3.概念补充

    • 磁北角度(newHeading.magneticHeading):相对于"磁北方向"产生的角度
    • 真北角度(newHeading.trueHeading):相对于"真北方向"产生的角度

    4.注意事项

    • 获取设备朝向前,先判断"磁力计"是否可用
      • [CLLocationManager headingAvailable];
    • 获取朝向信息前,判断当前朝向信息是否有效
      • 判断newHeading.headingAccuracy是否小于0,如果小于0,则无效
    • 注意"设备朝向"和"航向"的区别:
      • 设备朝向:是指手机的朝向
      • 航向:可以理解为设备的移动方向
    • 使用"磁力计"传感器获取设备朝向,不需要请求用户授权,因为设备朝向不涉及用户隐私

    5.测试环境

    • Xcode版本无要求(建议7.0+,因为不需要开发者账号也可以进行真机调试)
    • 必须要求真机设备(只有真机设备才有"磁力计"传感器)

    九.区域监听

    1.监听进入/离开区域动作

    • 概念解释
    • 区域:就是指划定的一块地域范围(比如圆形区域,则由区域中心和半径组成)
    • 区域监听:通过代码指定一个区域,然后当用户持握设备进入或离开指定区域,我们都能监听到
    • 监听指定区域
      1. 导入CoreLocation框架及对应的主头文件
      2. 创建CLLocationManager对象并设置代理
      3. 请求前台定位,或前台定位授权,并在info.plist文件中配置相应的key
        • [self.locationM requestAlwaysAuthorization]
        • 或[self.locationM requestWhenInUseAutorization]
      4. 创建一个区域,并开始监听
        • 创建区域中心:CLLocationCoordinate2D center = CLLocationCorrdinate2DMake(xxx,xxx)
        • 指定区域半径:CLLocationDistance radius = 1000
        • 创建区域:CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:@"喳喳"];
        • 开始监听指定区域:[self.locationM startMonitoringForRegion:region];
      5. 在对应的代理方法中监听区域状态
        • 进入监听区域:locationManager:didEnterRegion
        • 离开监听区域:locationManager:didExitRegion
    • 注意事项
      • 想要做区域监听,在iOS8.0之后,必须请求位置授权
      • 原因:区域间厅的原理就是获取用户的位置,然后再判断该位置是否在指定区域内,所以会涉及到用户的隐私(位置),而在iOS8.0之后,要想访问用户位置信息,就需要主动请求授权

    2.请求区域状态

    • 获取某个区域的当前状态
      • 监听某个区域时,只有进入或离开这个区域时,才能回调对应的方法,是一个进入或离开的动作
      • 如果想知道某一个区域的当前状态(识别用户是在区域内部,还是区域外部),则需要使用以下方法
        • [self.locationM requestStateForRegion:region]
      • 回调代理(请求某个区域状态时,回调的代理方法)
        • locationManager:didDetermineState:forRegion
    • 注意事项
      • 使用前,先判断区域监听是否可用
        • 代码:[CLLocationManager isMonitoringAvailabelForClass:[CLCircularRegion class]];
      • 注意区域半径是否大于最大区域监听半径(如果大于,则无法监听成功)
        • 代码:radius>self.locationM.maximumRegionMonitoringDistace
    • 常见问题
      • 区域监听,测试没有效果?
        1. 确定代码没有问题,是否有请求授权
        2. 尝试修改模拟器位置信息,触发进入区域或离开区域的动作
        3. 如果模拟器出现bug,定位不到,也会无法判定当前区域状态,所以,最后可以尝试重置模拟器

    十.地理编码/反地理编码

    1.功能实现

    • 概念解释
      • 地理编码:是指根据地址关键字,将其转换成对应的经纬度等信息
      • 反地理编码:是指根据经纬度信息,将其转换成为对应的省市区接到等信息
    • 地理编码
      1. 导入CoreLocation框架及对应的主头文件
      2. 创建CLGeocoder
      3. 根据地址关键字,进行地理编码
        • 直接根据地址进行地理编码,返回结果可能有多个,因为一个地点有重名
        • [self.geoC geocodeAddressString:@"北京" completionHandler:nil];
    • 反地理编码
      1. 导入CoreLocation框架及对应的主头文件
      2. 创建CLGeocoder
      3. 根据经纬度信息,进行反地理编码
        • [self.geoC reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:xxx longtitude:xxx] completionHandler:nil];

    2.CLPlacemark对象详解

    • CLPlacemark地标对象详解
      • location:CLLocation类型,位置对应信息,里面包含经纬度,海拔等信息
      • region:CLRegion类型,地标对象对应的区域
      • addressDictionary:NSDictionary类型,存放街道,省市等信息
      • name:NSString类型,地址全称
      • thoroughfare:NSString类型,街道名称
      • locality:NSString类型,城市名称
      • administrativeArea:NSString类型,省名称
      • country:NSString类型,国家名称
    • 测试环境:
      • 必须联网/Xcode版本不限/模拟器版本不限
    • 常见问题
      • 测试无数据:检查是否联网,如果是反地理编码,可以尝试更换经纬度再次尝试,因为有的经纬度没有对应的信息

    3.获取当前城市名称(定位+反地理编码)

    • 应用场景:
      • 社交app发表状态时显示位置
      • 团购app获取用户所在的区域
    • 实现步骤:
      • 定位
      • 定位后,根据位置信息,进行反地理编码

    十一.使用第三方框架进行定位

    • 主要原因:
      • 因为使用CoreLocation框架进行获取用户位置信息,是通过代理进行回调.
      • 而第三方框架将"代理模式"转换成"block模式",使用起来比较方便,而且额外增加了超时时间等功能
    • 框架信息:
      • 名称:locationManager(请自行到github上搜索获取)
      • 使用方法:参照该框架对应的readme文件
    • 注意事项:
      • 一般集成第三方框架到项目中,请先确保该框架没有问题,然后再向项目中集成

    十二.定位工具类的封装(代理模式到block模式的转换)

    • 主要思想就是,先记录下外界传递过来的block,然后在对应的代理方法里面执行这个block
    • 其实,实现定位还是使用代理,只不过向外界提供了一个block回调接口而已
  • 相关阅读:
    2.6
    zuoye
    练习1
    练习
    练习
    4
    3
    2
    1
    1.3
  • 原文地址:https://www.cnblogs.com/coderwjq/p/6212382.html
Copyright © 2020-2023  润新知