LocationManager.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. //
  2. // LocationManager.m
  3. // jiaPei
  4. //
  5. // Created by 张嵘 on 2018/9/20.
  6. // Copyright © 2018年 JCZ. All rights reserved.
  7. //
  8. #import "LocationManager.h"
  9. #import <CoreLocation/CoreLocation.h>
  10. static LocationManager *manger = nil;
  11. static dispatch_once_t onceToken;
  12. //复用annotationView的指定唯一标识
  13. static NSString *annotationViewIdentifier = @"com.Baidu.BMKPointAnnotation";
  14. @interface LocationManager () <BMKLocationAuthDelegate, BMKLocationManagerDelegate, BMKMapViewDelegate, BMKGeneralDelegate, BMKGeoCodeSearchDelegate>
  15. @property (nonatomic, strong) BMKMapManager *mapManager; //主引擎类
  16. @property (nonatomic, strong) BMKLocationManager *locationManager; //定位对象
  17. @property (nonatomic, strong) BMKUserLocation *userLocation;//当前位置对象
  18. @property (nonatomic, assign) BOOL locationLock;//单次定位锁
  19. @property (nonatomic, strong) LocCompletedBlock locCompletedBlock;//定位回调
  20. @property (nonatomic, strong) BMKMapView *mapView;//地图View类
  21. @property (nonatomic, assign) CGSize mapSize;//地图大小
  22. @property (nonatomic, strong) BMKGeoCodeSearch *searcher;//搜索对象
  23. @property (nonatomic, strong) SearchCompletedBlock searchCompletedBlock;//搜索回调
  24. @property (nonatomic, strong) ReverseCompletedBlock reverseCompletedBlock;//反地理编码回调
  25. @property (nonatomic, strong) CLLocationManager *cLLocationManager;
  26. @end
  27. @implementation LocationManager
  28. + (LocationManager *)sharedManager {
  29. dispatch_once(&onceToken, ^{
  30. manger = [[self alloc] init];
  31. });
  32. return manger;
  33. }
  34. - (instancetype)init {
  35. self = [super init];
  36. if (self) {
  37. // 初始化定位SDK
  38. [[BMKLocationAuth sharedInstance] checkPermisionWithKey:BaiDuMapAK authDelegate:self];
  39. //要使用百度地图,请先启动BMKMapManager
  40. _mapManager = [[BMKMapManager alloc] init];
  41. /**
  42. 百度地图SDK所有API均支持百度坐标(BD09)和国测局坐标(GCJ02),用此方法设置您使用的坐标类型.
  43. 默认是BD09(BMK_COORDTYPE_BD09LL)坐标.
  44. 如果需要使用GCJ02坐标,需要设置CoordinateType为:BMK_COORDTYPE_COMMON.
  45. */
  46. if ([BMKMapManager setCoordinateTypeUsedInBaiduMapSDK:BMK_COORDTYPE_BD09LL]) {
  47. NSLog(@"经纬度类型设置成功");
  48. } else {
  49. NSLog(@"经纬度类型设置失败");
  50. }
  51. //启动引擎并设置AK并设置delegate
  52. BOOL result = [_mapManager start:BaiDuMapAK generalDelegate:self];
  53. if (!result) {
  54. NSLog(@"启动引擎失败");
  55. }
  56. _cLLocationManager = [[CLLocationManager alloc] init];
  57. [_cLLocationManager requestWhenInUseAuthorization];
  58. }
  59. return self;
  60. }
  61. - (void)dealloc {
  62. _mapView.delegate = nil;
  63. }
  64. #pragma mark - Custom Way
  65. /**
  66. 根据大小创建地图
  67. @param size 大小
  68. @return 返回地图
  69. */
  70. - (BMKMapView *)getMapViewWithSize:(CGSize)size {
  71. _mapSize = size;
  72. return self.mapView;
  73. }
  74. /**
  75. 单次定位
  76. @param completeBlock 定位回调
  77. */
  78. - (void)updateLocationWithCompleteBlock:(LocCompletedBlock)completeBlock {
  79. @weakify(self)
  80. self.locationLock = YES;
  81. _locCompletedBlock = completeBlock;
  82. self.locationManager.distanceFilter = kCLDistanceFilterNone;
  83. [self.locationManager requestLocationWithReGeocode:YES withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {
  84. @strongify(self)
  85. if (_locCompletedBlock) {
  86. _locCompletedBlock(location != nil, location.location);
  87. }
  88. if (error) [self showErrorAlertWithError:error];
  89. }];
  90. }
  91. /**
  92. 连续定位
  93. @param distanceFilter 设定定位的最小更新距离。默认为 kCLDistanceFilterNone
  94. @param completeBlock 定位回调
  95. */
  96. - (void)updateLocationWithDistanceFilter:(NSInteger)distanceFilter CompleteBlock:(LocCompletedBlock)completeBlock {
  97. [self.locationManager startUpdatingLocation];
  98. self.locationManager.distanceFilter = distanceFilter? distanceFilter : kCLDistanceFilterNone;
  99. _locCompletedBlock = completeBlock;
  100. }
  101. /**
  102. 返回地址信息搜索结果
  103. @param address 地址(必填)
  104. @param city 城市(选填)
  105. @param completeBlock 搜索回调
  106. */
  107. - (void)onGetGeoCodeWithAddress:(NSString *)address City:(NSString *)city completeBlock:(SearchCompletedBlock)completeBlock {
  108. BMKGeoCodeSearchOption *geoCodeSearchOption = [[BMKGeoCodeSearchOption alloc]init];
  109. geoCodeSearchOption.city= city;
  110. geoCodeSearchOption.address = address;
  111. [self.searcher geoCode:geoCodeSearchOption];
  112. _searchCompletedBlock = completeBlock;
  113. }
  114. /**
  115. 返回反地理编码搜索结果
  116. @param location 定位
  117. @param completeBlock 搜索回调
  118. */
  119. - (void)onGetReverseGeoCodeWithLocation:(CLLocation *)location completeBlock:(ReverseCompletedBlock)completeBlock {
  120. BMKReverseGeoCodeSearchOption *reverseGeoCodeSearchOption = [[BMKReverseGeoCodeSearchOption alloc]init];
  121. reverseGeoCodeSearchOption.location = location.coordinate;
  122. [self.searcher reverseGeoCode:reverseGeoCodeSearchOption];
  123. _reverseCompletedBlock = completeBlock;
  124. }
  125. /**
  126. 错误弹窗
  127. */
  128. - (void)showErrorAlertWithError:(NSError *)error {
  129. switch (error.code) {
  130. case BMKLocationErrorDenied: {
  131. [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"请在iPhone的“设置”-“隐私”-“定位服务”功能中,找到“极速驾培”打开位置访问权限" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil completion:nil];
  132. }
  133. break;
  134. default:
  135. break;
  136. }
  137. [_locationManager stopUpdatingLocation];
  138. }
  139. /**
  140. 开始定位
  141. */
  142. - (void)beginLocation{
  143. [self.locationManager startUpdatingLocation];
  144. [self.locationManager startUpdatingHeading];
  145. }
  146. #pragma mark - BMKLocationAuthDelegate 定位鉴权代理
  147. /**
  148. * @brief 返回授权验证错误
  149. * @param iError 错误号 : 为0时验证通过,具体参加BMKLocationAuthErrorCode
  150. */
  151. - (void)onCheckPermissionState:(BMKLocationAuthErrorCode)iError {
  152. if (_locCompletedBlock) {
  153. _locCompletedBlock(NO, nil);
  154. }
  155. switch (iError) {
  156. case BMKLocationAuthErrorUnknown:
  157. NSLog(@"未知错误");
  158. break;
  159. case BMKLocationAuthErrorSuccess:
  160. NSLog(@"鉴权成功");
  161. break;
  162. case BMKLocationAuthErrorNetworkFailed:
  163. NSLog(@"因网络鉴权失败");
  164. break;
  165. case BMKLocationAuthErrorFailed:
  166. NSLog(@"KEY非法鉴权失败");
  167. break;
  168. default:
  169. break;
  170. }
  171. }
  172. /**
  173. 联网结果回调
  174. @param iError 联网结果错误码信息,0代表联网成功
  175. */
  176. - (void)onGetNetworkState:(int)iError {
  177. if (0 == iError) {
  178. NSLog(@"联网成功");
  179. } else {
  180. NSLog(@"联网失败:%d", iError);
  181. if (_searchCompletedBlock) {
  182. _searchCompletedBlock(NO, nil, iError);
  183. }
  184. if (_reverseCompletedBlock) {
  185. _reverseCompletedBlock(NO, nil, iError);
  186. }
  187. }
  188. }
  189. #pragma mark - BMKMapViewDelegate 地图代理
  190. #pragma mark - BMKGeoCodeSearchDelegate 搜索代理
  191. - (void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeSearchResult *)result errorCode:(BMKSearchErrorCode)error {
  192. if (_searchCompletedBlock) {
  193. _searchCompletedBlock(result? YES : NO, result, error);
  194. }
  195. }
  196. - (void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeSearchResult *)result errorCode:(BMKSearchErrorCode)error {
  197. if (_reverseCompletedBlock) {
  198. _reverseCompletedBlock(result ? YES : NO, result, error);
  199. }
  200. }
  201. #pragma mark - BMKLocationManagerDelegate 定位代理
  202. /**
  203. 用户拒绝开启定位服务等原因导致的定位失败会调用的方法
  204. @brief 当定位发生错误时,会调用代理的此方法。
  205. @param manager 定位 BMKLocationManager 类。
  206. @param error 返回的错误,参考 CLError 。
  207. */
  208. - (void)BMKLocationManager:(BMKLocationManager *)manager didFailWithError:(NSError *)error {
  209. if (error) [self showErrorAlertWithError:error];
  210. }
  211. /**
  212. 处理位置坐标更新
  213. @brief 连续定位回调函数
  214. @param manager 定位 BMKLocationManager 类。
  215. @param location 定位结果,参考BMKLocation。
  216. @param error 错误信息。
  217. */
  218. - (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
  219. if (location) {
  220. self.userLocation.location = location.location;
  221. //实现该方法,否则定位图标不出现
  222. [_mapView updateLocationData:self.userLocation];
  223. //设置当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
  224. _mapView.centerCoordinate = self.userLocation.location.coordinate;
  225. if (_locCompletedBlock) {
  226. _locCompletedBlock(location != nil , location.location);
  227. }
  228. [_locationManager stopUpdatingLocation];
  229. //发起反向地理编码检索
  230. // _searcher =[[BMKGeoCodeSearch alloc]init];
  231. // _searcher.delegate = self;
  232. // BMKReverseGeoCodeSearchOption *reverseGeoCodeSearchOption = [[BMKReverseGeoCodeSearchOption alloc]init];
  233. // reverseGeoCodeSearchOption.location = location.location.coordinate;
  234. // [_searcher reverseGeoCode:reverseGeoCodeSearchOption];
  235. }
  236. }
  237. #pragma mark - Lazy loading
  238. - (BMKLocationManager *)locationManager {
  239. if (!_locationManager) {
  240. _locationManager = [[BMKLocationManager alloc] init];
  241. _locationManager.delegate = self;
  242. _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;
  243. _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  244. _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
  245. _locationManager.pausesLocationUpdatesAutomatically = NO;
  246. _locationManager.allowsBackgroundLocationUpdates = NO;
  247. _locationManager.locationTimeout = 10;
  248. }
  249. return _locationManager;
  250. }
  251. - (BMKUserLocation *)userLocation {
  252. if (!_userLocation) {
  253. _userLocation = [[BMKUserLocation alloc] init];
  254. }
  255. return _userLocation;
  256. }
  257. - (BMKMapView *)mapView {
  258. if (!_mapView) {
  259. _mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0,0,_mapSize.width, _mapSize.height)];
  260. //开启定位服务
  261. [self beginLocation];
  262. //设置mapView的代理
  263. _mapView.delegate = self;
  264. //当前地图类型
  265. _mapView.mapType = BMKMapTypeStandard;
  266. //设置地图比例尺级别
  267. _mapView.zoomLevel = 14.7;
  268. //设置显示定位图层
  269. _mapView.showsUserLocation = YES;
  270. //设置定位模式为普通模式
  271. _mapView.userTrackingMode = BMKUserTrackingModeNone;
  272. //设定显式比例尺
  273. _mapView.showMapScaleBar = YES;
  274. //配置定位图层个性化样式,初始化BMKLocationViewDisplayParam的实例
  275. BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init];
  276. //设置定位图标(屏幕坐标)X轴偏移量为0
  277. param.locationViewOffsetX = 0;
  278. //设置定位图标(屏幕坐标)Y轴偏移量为0
  279. param.locationViewOffsetY = 0;
  280. //设置定位图层locationView在最上层(也可设置为在下层)
  281. param.locationViewHierarchy = LOCATION_VIEW_HIERARCHY_TOP;
  282. //设置显示精度圈(因“需求:可改变精度圈大小”,关闭默认精度圈)
  283. param.isAccuracyCircleShow = NO;
  284. //跟随态旋转角度是否生效
  285. param.isRotateAngleValid = YES;
  286. //更新定位图层个性化样式
  287. [_mapView updateLocationViewWithParam:param];
  288. }
  289. return _mapView;
  290. }
  291. - (BMKGeoCodeSearch *)searcher {
  292. if (!_searcher) {
  293. _searcher =[[BMKGeoCodeSearch alloc]init];
  294. _searcher.delegate = self;
  295. }
  296. return _searcher;
  297. }
  298. @end