前言
本文重点:
- 定位
- 地理编码
- 判断目标经纬度是否在大陆 :https://kunnan.blog.csdn.net/article/details/119685526
通过经纬度进行判断。利用高德SDK进行判断。(
如果是手动输入位置信息就进行逆地理编码获取经纬度
)
I、地理编码:geocode
- 设置高德SDK apiKey
[AMapServices sharedServices].apiKey = @"xxx";
1.1地理编码 API 服务地址
1.2适用场景
- 地理编码:将详细的结构化地址转换为高德经纬度坐标。且支持对地标性名胜景区、建筑物名称解析为高德经纬度坐标。1、结构化地址举例:北京市朝阳区阜通东大街6号转换后经纬度:116.480881,39.989410 2、地标性建筑举例:天安门转换后经纬度:116.397499,39.908722
- 逆地理编码:将经纬度转换为详细结构化的地址,且返回附近周边的POI、AOI信息。1、例如:116.480881,39.989410 转换地址描述后:北京市朝阳区阜通东大街6号
1.3结构化地址信息address
请求参数的要求
- 规则遵循:国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦,如:北京市朝阳区阜通东大街6号。
- 另外这个API的对地址的具体要求是:结构化地址的定义:首先,地址肯定是一串字符,内含国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦等建筑物名称。按照由大区域名称到小区域名称组合在一起的字符。一个有效的地址应该是独一无二的。注意:针对大陆、港、澳地区的地理编码转换时可以将国家信息选择性的忽略,但省、市、城镇等级别的地址构成是不能忽略的。暂时不支持返回台湾省的详细地址信息。
- 需要对请求参数不准确,进行异常处理
CRMgeoDto *dto = [CRMgeoDto mj_objectWithKeyValues:responseObject]; if(dto.status.integerValue == 1){ // 获取经纬度 ,如果失败,提示【获取经纬度失败,请输入准确的经营地址!】 void (^noLocationdataBlock)(void) = ^void(void) { [SVProgressHUD showInfoWithStatus:@"获取经纬度失败,请输入准确的经营地址!"]; }; // responseObject: { // status = 1; // info = OK; // infocode = 10000; // count = 0; // geocodes = ( // ); if(dto.geocodes.count<=0){ noLocationdataBlock(); return ; } CRMgeocodesDto *geocodesDto = dto.geocodes.firstObject; if([NSStringQCTtoll isBlankString:geocodesDto.location]){ noLocationdataBlock(); return ; } NSArray *array = [responseObject[@"geocodes"][0][@"location"] componentsSeparatedByString:@","]; if(array.count<=1){ noLocationdataBlock(); return; }
1.4接口返回的格式
- 返回的dto模型定义
- location
location = "114.468664,38.037057";
2020-04-10 11:43:29.914038+0800 Housekeeper[943:136269] responseObject: { count = 1; geocodes = ( { adcode = 350503; building = { name = ( ); type = ( ); }; city = "\U6cc9\U5dde\U5e02"; citycode = 0595; country = "\U4e2d\U56fd"; district = "\U4e30\U6cfd\U533a"; "formatted_address" = "\U798f\U5efa\U7701\U6cc9\U5dde\U5e02\U4e30\U6cfd\U533a\U5bcc\U5927\U53a6"; level = "\U5174\U8da3\U70b9"; location = "118.620285,24.908597"; neighborhood = { name = ( ); type = ( ); }; number = ( ); province = "\U798f\U5efa\U7701"; street = ( ); township = ( ); } ); info = OK; infocode = 10000; status = 1; }
1.5 通过逆地理编码进行判断是否在大陆
- 判断目标经纬度是否在大陆 :https://kunnan.blog.csdn.net/article/details/119685526
通过经纬度进行判断。利用高德SDK进行判断。(
如果是手动输入位置信息就进行逆地理编码获取经纬度
)
II、定位
2.1 获取定位信息
- 使用方法
[[ProjectMethod shareProjectMethod] SingleLocation:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) { [[QCT_Common getCurrentVC] hideHUD]; // 定位失败 if (error) { if (error.code == AMapLocationErrorLocateFailed) { return; } NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription); NSString *UserInfo = error.userInfo[@"NSLocalizedDescription"]; [self showHUDMessage:UserInfo?UserInfo:@"定位失败请重新再试!"]; } // 定位成功 if (regeocode) { NSLog(@"reGeocode:%@", regeocode); if (regeocode) { if([ERPAMapLocationTool inChineseMainlandWithCLLocation:location regeocode:regeocode]){ }else{ //如不在大陆,则不允许其修改定位,提示“您最新定位不在支持范围内!”。 [self showHUDMessage:@"您最新定位不在支持范围内!"]; return; } NSString *text = [NSString stringWithFormat:@"%@%@%@",regeocode.street,regeocode.number,regeocode.POIName]; self.address = regeocode.formattedAddress ?regeocode.formattedAddress :@""; /** provinceName (string, optional): 省名称 , cityName (string, optional): 市名称 , areaName (string, optional): 区名称 , address (string, optional): 详细位置 , longitude1 (string, optional): 经度 , longitude2 (string, optional): 纬度 , nature (integer, optional): 客户类型 , */ // 需要保存经纬度 NSString* lon = [NSString stringWithFormat:@"%f", location.coordinate.longitude]; NSString* lat = [NSString stringWithFormat:@"%f", location.coordinate.latitude]; // 保持起来。更新TV weakSelf.longitude1 = lon; weakSelf.longitude2 = lat; [_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:1 inSection:1]] withRowAnimation:UITableViewRowAnimationNone ]; [weakSelf setupk_API_Account_Merchant_UpdateMerchantGeo]; } } }];
- SingleLocation的实现
- (void)SingleLocation:(AMapLocatingCompletionBlock)completionBlock{ // 先判断状态,比如是否进行授权 self.location = [[AMapLocationManager alloc]init]; // 判断用户是否授权应用获取定位权限 // iOS开发检测是否开启定位: showAlert if (![QCTSession isHasLocationAuthorityWithisShowAlert:YES]) { return; } // [[QCT_Common getCurrentVC] showHUDProgressWithMessage:@"定位中..." style:MBPHUDProgressStyleAnnular]; [[QCT_Common getCurrentVC] showHUDProgressWithMessage:@"定位中..." style:MBPHUDProgressStyleNormal]; [self.location setDesiredAccuracy:kCLLocationAccuracyHundredMeters]; // 定位超时时间,最低2s,此处设置为2s self.location.locationTimeout = 2; // 逆地理请求超时时间,最低2s,此处设置为2s self.location.reGeocodeTimeout = 2; // [self showHUDProgressWithMessage:@"定位中..." style:MBPHUDProgressStyleAnnular]; [self.location requestLocationWithReGeocode:YES completionBlock:completionBlock]; // [self hideHUD]; }
- 针对kCLAuthorizationStatusNotDetermined的处理【[AMapLocationKit] 要在iOS 11及以上版本使用后台定位服务, 需要实现amapLocationManager:doRequireLocationAuth: 代理方法问题及解决方案】
/** 1、 限制境外定位 (优化定位权限检查的处理逻辑:主要针对iOS13访问位置信息信息新增的【下次询问】的场景):iOS 13新增App地理位置访问“仅允许一次” 1.1):测试方法: 先设置【使用app时允许】,再去系统的设置修改定位信息的权限为:【下次询问】。回到app去更新定位信息。 定位之前,先检测权限,如果是kCLAuthorizationStatusNotDetermined的时候,需要实现这个方法,来让用户进行选择。 kCLAuthorizationStatusNotDetermined //用户没有选择是否要使用定位服务(弹框没选择,或者根本没有弹框) */ - (void)amapLocationManager:(AMapLocationManager *)manager doRequireLocationAuth:(CLLocationManager*)locationManager { [locationManager requestAlwaysAuthorization]; }
- 监听定位状态
- (void)amapLocationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { switch (status) { case kCLAuthorizationStatusNotDetermined: break; case kCLAuthorizationStatusDenied: { [QCTSession setupkCLAuthorizationStatusDenied]; } break; default: break; } // [[QCT_Common getCurrentVC] hideHUD]; }
- 修改定位未开启的提示语 setupkCLAuthorizationStatusDenied
+(void)setupkCLAuthorizationStatusDenied{ // [[QCT_Common getCurrentVC] hideHUD]; [LBAlertController showAlertTitle:@"定位服务未开启" content:@"请进入系统「设置」》「隐私」》「定位服务」\"中打开开关,并允许全城淘使用定位服务" cancelString:@"取消" cancleBlock:nil sureString:@"立即开启" sureBlock:^{ // 需要在info.plist中添加 URL types 并设置一项URL Schemes为prefs IOS10 以后不起作用 if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]){ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; } } currentController:[QCT_Common getCurrentVC]]; return; [LBAlertController showAlertTitle:@"无法使用定位" content:@"请在iPhone的\"设置-隐私-定位\"中允许访问地理位置。" cancelString:@"取消" cancleBlock:nil sureString:@"去设置" sureBlock:^{ // 需要在info.plist中添加 URL types 并设置一项URL Schemes为prefs IOS10 以后不起作用 if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]){ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; } } currentController:[QCT_Common getCurrentVC]]; }
2.2 权限的判断: 判断用户是否授权应用获取定位权限
- 使用方法
if (![QCTSession isHasLocationAuthorityWithisShowAlert:YES]) { return; }
- isHasLocationAuthorityWithisShowAlert
//iOS 跳转系统设置打开定位页面 +(BOOL)isHasLocationAuthorityWithisShowAlert:(BOOL)showAlert{ CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; //应用程序的定位权限被限制 //拒绝获取定位 if (status == kCLAuthorizationStatusRestricted || status == kCLAuthorizationStatusDenied) { NSLog(@"NSLog 没有获取地理位置的权限"); if (showAlert) { [LBAlertController showAlertTitle:@"无法使用定位" content:@"请在iPhone的\"设置-隐私-定位\"中允许访问地理位置。" cancelString:@"取消" cancleBlock:nil sureString:@"去设置" sureBlock:^{ // 需要在info.plist中添加 URL types 并设置一项URL Schemes为prefs IOS10 以后不起作用 if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]){ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; } } currentController:[QCT_Common getCurrentVC]]; } return NO; }else if (status == kCLAuthorizationStatusNotDetermined){//用户尚未对该应用程序作出选择,如果是采用高德的SDK定位可以不执行。只要实现amapLocationManager:doRequireLocationAuth: 代理方法即可 CLLocationManager *manager = [[CLLocationManager alloc] init]; if([manager respondsToSelector:@selector(requestWhenInUseAuthorization)]){ [manager requestWhenInUseAuthorization]; }; } NSLog(@" 获取位置权限正常=============="); return YES; }
2.3 处理【非首次安装允许定位权限弹框】
- AppDelegate中检测定位权限
打开app提示定位权限弹框,针对iOS13 每次都要下次询问,为了用户体验去掉
/** 非首次安装提示定位权限弹框 { CLLocationManager *locationManager; } */ - (void) setupgetUserLocationAuth{ NSLog(@"setupgetUserLocationAuth : 非首次安装提示定位权限弹框"); if (![self getUserLocationAuth]) {//提示允许访问 locationManager = [[CLLocationManager alloc] init]; [locationManager requestAlwaysAuthorization]; //创建CLLocationManager对象,在使用定位服务前调用requestWhenInUseAuthorization()。提示 [locationManager requestWhenInUseAuthorization]; } } - (BOOL)getUserLocationAuth { BOOL result = NO; switch ([CLLocationManager authorizationStatus]) { case kCLAuthorizationStatusNotDetermined: break; case kCLAuthorizationStatusRestricted: break; case kCLAuthorizationStatusDenied: break; case kCLAuthorizationStatusAuthorizedAlways: result = YES; break; case kCLAuthorizationStatusAuthorizedWhenInUse: result = YES; break; default: break; } return result; }
III、 判断新的定位地址是否在大陆范围内
- 判断目标经纬度是否在大陆 :https://kunnan.blog.csdn.net/article/details/119685526
通过经纬度进行判断。利用高德SDK进行判断。(
如果是手动输入位置信息就进行逆地理编码获取经纬度
)