地图定位
一:地图与定位基本框架(MapKit时基于CoreLocation实现的夜可以实现定位)
二:开发常用技术
- LBS:基于位置的服务
- SoLoMo:社交,本地,移动化
三:定位授权提示(iOS之前)
四:每个一段距离定位
五:后台服务:默认只能在前台服务
plist文件中
对应plist文件的值(数组)
六:基于基站定位
七:iOS8以上的服务
- 前台定位
定位服务开启
开启授权
后台服务(可以不勾选后台模式)
- 定位服务开
开启后台授权
授权改变 // 如果授权状态发生变化时,调用 // 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+ NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url]; } }else { NSLog(@"定位服务关闭"); } break; } case kCLAuthorizationStatusAuthorizedAlways: { NSLog(@"前后台定位授权"); break; } case kCLAuthorizationStatusAuthorizedWhenInUse: { NSLog(@"前台定位授权"); break; } default: break; } }
八:系统适配
1:根据系统的版本
2:根据方法的响应
3:iOS9中版本判断
九:提示用户开启定位
- iOS-8之前:需要截图
- iOS8之后:跳转URL
十:关于iOS9定位
后台定位需要增加一个属性(在勾选后台活着增加plist属性之后)
iOS9中请求一次定位信息
十一:id加范型->is Kind of
判断当前位置是否可用
或者
十二:指南针
在创建管理者设置代理 // 获取当前设备朝向 [self.locationM startUpdatingHeading]; 然后在代理方法中实现下面的代码 // 已经更新到用户设备朝向时调用 -(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { // magneticHeading : 距离磁北方向的角度 // trueHeading : 真北 // headingAccuracy : 如果是负数,代表当前设备朝向不可用 if (newHeading.headingAccuracy < 0) { return; } // 角度 CLLocationDirection angle = newHeading.magneticHeading; // 角度-> 弧度 double radius = angle / 180.0 * M_PI; // 反向旋转图片(弧度) [UIView animateWithDuration:0.5 animations:^{ self.compassView.transform = CGAffineTransformMakeRotation(-radius); }]; }
十三:区域监听
判断区域类
判断区域大小
区域变化
十四:监听区域的时候调用的代理方法
1.进入 /** * 进入区域调用(是一个动作) * * @param manager 位置管理者 * @param region 区域 */ -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { NSLog(@"进入区域"); self.noticeLabel.text = @"小码哥欢迎你, 给你技术"; } 2.离开 /** * 离开某个区域调用 * * @param manager 位置管理者 * @param region 区域 */ -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { NSLog(@"离开区域"); self.noticeLabel.text = @"祝大神三期找到30K"; } 3.判断和区域的位置对应 /** * 请求某个区域的状态是调用 * * @param manager 位置管理者 * @param state 状态 * @param region 区域 */ -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region { // CLRegionStateUnknown, 未知状态 // CLRegionStateInside, // 在区域内部 // CLRegionStateOutside // 区域外面 if(state == CLRegionStateInside) { self.noticeLabel.text = @"小码哥欢迎你, 给你技术"; }else if (state == CLRegionStateOutside) { self.noticeLabel.text = @"祝大神三期找到30K"; } } 4.失败 /** * 监听区域失败时调用 * * @param manager 位置管理者 * @param region 区域 * @param error 错误 */ -(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error { // 经验: 一般在这里, 做移除最远的区域 // [manager stopMonitoringForRegion:最远区域] }
十五:编码与反编码
地理编码:位置名称->经纬度 NSString *address = self.addressTV.text; // 容错 if([address length] == 0) return; [self.geoC geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { // CLPlacemark : 地标 // location : 位置对象 // addressDictionary : 地址字典 // name : 地址详情 // locality : 城市 if(error == nil) { CLPlacemark *pl = [placemarks firstObject]; self.addressTV.text = pl.name; self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue; self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue; }else { NSLog(@"错误"); } }]; 反地理编码:经纬度->位置名称 // 获取用户输入的经纬度 double latitude = [self.latitudeTF.text doubleValue]; double longitude = [self.longitudeTF.text doubleValue]; CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude]; // 反地理编码(经纬度---地址) [self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { if(error == nil) { CLPlacemark *pl = [placemarks firstObject]; self.addressTV.text = pl.name; self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue; self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue; }else { NSLog(@"错误"); } }]; 注:double快速转string
十六:第三方->LocationManager
基本使用 INTULocationManager *locMgr = [INTULocationManager sharedInstance]; // delayUntilAuthorized 超时计时从什么时候开始 INTULocationRequestID requestID = [locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyCity timeout:3.0 delayUntilAuthorized:NO block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) { if (status == INTULocationStatusSuccess) { NSLog(@"---%@", currentLocation); }else { NSLog(@"错误 %zd", status); } }]; // 会执行block内容 // [[INTULocationManager sharedInstance] forceCompleteLocationRequest:requestID]; // 取消位置请求 [[INTULocationManager sharedInstance] cancelLocationRequest:requestID];
在使用的时候爆了一个错误
解决办法:
十七:经典实战,将代理转Blcok
定义一个Block typedef void(^ResultBlock)(CLLocation *location, CLPlacemark *pl, NSString *error); 声明一个带Block方法 - (void)getCurrentLocation:(ResultBlock)block; 实现方法 - (void)getCurrentLocation:(ResultBlock)block { // 记录代码块 self.block = block; // 获取用户位置信息 if([CLLocationManager locationServicesEnabled]) { [self.locationM startUpdatingLocation]; }else { self.block(nil, nil, @"定位服务未开启"); } } 在创建位置管理者的时候实现项目内部文件对应属性值的判断,根据不同的值提示开发者 if (!_locationM) { _locationM = [[CLLocationManager alloc] init]; _locationM.delegate = self; // iOS8.0之后, 必须手动请求定位授权 // 获取info.plist 里面的键值对 NSDictionary *infoDic = [NSBundle mainBundle].infoDictionary; // NSLog(@"%@", infoDic); if (isIOS(8.0)) { // [_locationM requestAlwaysAuthorization]; // [_locationM requestWhenInUseAuthorization]; // 获取前后台定位描述(看其他开发者到底有没有添加这个key) NSString *alwaysStr = infoDic[@"NSLocationAlwaysUsageDescription"]; // 获取前后台定位描述(看其他开发者到底有没有添加这个key) NSString *whenInUseStr = infoDic[@"NSLocationWhenInUseUsageDescription"]; // 判断其它开发者, 到底填写的是哪个key if([alwaysStr length] > 0) { [_locationM requestAlwaysAuthorization]; } else if ([whenInUseStr length] > 0) { [_locationM requestWhenInUseAuthorization]; // 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates NSArray *backModes = infoDic[@"UIBackgroundModes"]; if (![backModes containsObject:@"location"]) { NSLog(@"当前授权模式是前台定位授权, 如果想要在后台获取位置, 需要勾选后台模式location updates"); }else // 代表当前勾选后台模式, 而且是前台定位授权 { if(isIOS(9.0)) { _locationM.allowsBackgroundLocationUpdates = YES; } } }else { NSLog(@"如果在iOS8.0之后获取用户位置, 必须主动填写info.plist文件中的key NSLocationAlwaysUsageDescription 或者NSLocationWhenInUseUsageDescription"); } }else // ios8.0之前 { // 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates NSArray *backModes = infoDic[@"UIBackgroundModes"]; if (![backModes containsObject:@"location"]) { NSLog(@"当前授权模式, 如果想要在后台获取位置, 需要勾选后台模式location updates"); } } } return _locationM; 实现位置更新方法 #pragma mark -CLLocationManagerDelegate /** * 定位到之后调用 * * @param manager 位置管理者 * @param locations 位置数组 */ -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { CLLocation *location = [locations lastObject]; // 判断位置是否可用 if (location.horizontalAccuracy >= 0) { [self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { if (error == nil) { CLPlacemark *pl = [placemarks firstObject]; self.block(location, pl, nil); }else { self.block(location, nil, @"反地理编码失败"); } }]; } // 如果只需要获取一次位置, 那么在此处停止获取用户位置 [manager stopUpdatingLocation]; } 实现授权改变 /** * 当前授权状态发生改变时调用 * * @param manager 位置管理者 * @param status 状态 */ -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { switch (status) { // 用户还未决定 case kCLAuthorizationStatusNotDetermined: { NSLog(@"用户还未决定"); break; } // 问受限 case kCLAuthorizationStatusRestricted: { NSLog(@"访问受限"); self.block(nil, nil, @"访问受限"); break; } // 定位关闭时和对此APP授权为never时调用 case kCLAuthorizationStatusDenied: { // 定位是否可用(是否支持定位或者定位是否开启) if([CLLocationManager locationServicesEnabled]) { NSLog(@"定位开启,但被拒"); self.block(nil, nil, @"被拒绝"); }else { NSLog(@"定位关闭,不可用"); self.block(nil, nil, @"定位关闭,不可用"); } break; } // 获取前后台定位授权 case kCLAuthorizationStatusAuthorizedAlways: // case kCLAuthorizationStatusAuthorized: // 失效,不建议使用 { NSLog(@"获取前后台定位授权"); break; } // 获得前台定位授权 case kCLAuthorizationStatusAuthorizedWhenInUse: { NSLog(@"获得前台定位授权"); break; } default: break; } }
总结
开发经验
- 1:start开启服务,stop停止服务
- 2:用户隐私提示说明(交给产品经理)
- 3:重大位置-基站
关于地图术语:
1.方位简写
- E东
- W西
- N北
- S南
2.位置的计算
- 1’ = 111km
3.术语
- coordinate:经纬度
- altitude:海拔高度
- course航向
- distanceFromLocation。计算距离
4.返回数值
- 负值代表不可用
5.指南针方向
- megneticHeading:磁北
- tureHeading:真北
- headingAcceracy:负则不可用
使用总结
- 地图简单总
- 转弧
Xcode模拟器安装
解压
解压后放倒对应的路径中
本博文由博主根据资料或其他优秀博文整理而成,转载请注明出处,谢谢!