携手创造,共同生长!这是我参与「日新计划 8 月更文挑战」的第5天,点击查看活动概况

导言

需求布景:收款页面需求恳求IP定位API获取经纬度,因为高德的API的库不准确(没有实时更新),运用公司决议换腾讯API。

自己推荐app侧的SDK定位运用高德,因为高德SDK定位更准确,过错信息也更具体。

app侧运用定位的相关功用:

  1. 商户进件APP: 商户概况的从头定位,修改进件信息时的商户地址定位、支付终端绑定的从头定位、新增拜访记载的定位、新增/修改企业的企业地址定位

  2. 商户端APP: 终端管理的设备定位、店肆定位。

iOS小技能:封装定位SDK,统一数据模型和错误处理。

I 单次定位

iOS小技能:封装定位SDK,统一数据模型和错误处理。

1.1 腾讯SDK(TencentLBS)

/**
 * 设置用户是否赞同隐私协议方针
 * <p>调用其他接口前有必要首要调用此接口进行用户是否赞同隐私方针的设置,传入YES后才能正常运用定位功用,否则TencentLBSLocationManager初始化不成功,回来nil,定位功用均无法运用</p>
 * @param isAgree 是否赞同隐私方针
 */
+ (void)setUserAgreePrivacy:(BOOL) isAgree;
/**
 *  单次定位
 *
 *  该办法为下面办法的一层封装。
 *  level默认是TencentLBSRequestLevelPoi
 *  timeout默认是10s
 */
- (BOOL)requestLocationWithCompletionBlock:(TencentLBSLocatingCompletionBlock)completionBlock;
// 先履行署理办法tencentLBSDidChangeAuthorization再履行此回调
/**
 * 当时归于含糊定位状况时,通过该接口恳求暂时的完全定位精度的权限
 * @param purposeKey 需求在info.plist中配置NSLocationTemporaryUsageDescriptionDictionary key值和对应的恳求该权限的描绘理由
 * @param completion 在弹框让用户选择后的用户的反馈,假如用户颁发该权限,block中的参数为nil,假如未颁发,block中的参数将为PurposeKey对于的key的描绘(如PurposeKey=TemporaryPurposKey_1)
 */
- (void)requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(NSString *)purposeKey
                                                     completion:(void (^)(NSError *))completion;

初始化locationManager

- (TencentLBSLocationManager *)locationManager{
    if(_locationManager == nil){
        _locationManager = [[TencentLBSLocationManager alloc] init];
        [self configLocationManager];
    }
    return _locationManager;
}
- (void)configLocationManager {
    [TencentLBSLocationManager setUserAgreePrivacy:YES];
  _locationManager = [[TencentLBSLocationManager alloc] init];
    [_locationManager setDelegate:self];
    [_locationManager setPausesLocationUpdatesAutomatically:NO];
//    [_locationManager setAllowsBackgroundLocationUpdates:YES];
    [_locationManager setApiKey:@"-----6JBM3"];//
//
    //若获取的drLocatin中带有地址信息,可
    [_locationManager setRequestLevel:TencentLBSRequestLevelAdminName];
//处理初次定位,原生API处理初次定位(推荐)QCTLocationServiceUtil isHasLocationAuthorityWithisShowAlert:YES block
    //不运用SDK的办法
//    CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
//    if (authorizationStatus == kCLAuthorizationStatusNotDetermined) {
//        [self.locationManager requestWhenInUseAuthorization];
//    }
//
}

单次定位

- (void)SingleLocation:(TencentLBSLocatingCompletionBlock)completionBlock{
__weak __typeof__(self) weakSelf = self;
//处理初次定位
[QCTLocationServiceUtil isHasLocationAuthorityWithisShowAlert:YES block:^(id  _Nonnull sender) {
    //含糊定位适配
    [weakSelf setuprequestLocationWithCompletionBlock:completionBlock];
}];
}
- (void)setuprequestLocationWithCompletionBlock:(TencentLBSLocatingCompletionBlock)completionBlock{
    self.block =completionBlock;// 用于适配iOS14
    [SVProgressHUD showWithStatus:@"定位中.."];
    //1.iOS 含糊定位适配
//    能够运用以下办法判别当时应用的定位精度权限,事务可根据相应的值做出不同的操作:
    if (@available(iOS 14.0, *)) {
        TencentLBSAccuracyAuthorization accAuthor = [TencentLBSLocationManager accuracyAuthorization];
        if(accAuthor == TencentLBSAccuracyAuthorizationReducedAccuracy){
    //        当时归于含糊定位状况时,通过该接口恳求暂时的完全定位精度的权限
            //权限的变更会通过TencentLBSLocationManagerDelegate中的 - (void)tencentLBSDidChangeAuthorization:(TencentLBSLocationManager *)manager办法回调
                                self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey = YES;
                    // 记载当时是否向用户恳求临时开启一次准确方位权限,用于【假如定位精度权限变更为准确的时分,再次更新定位信息】
            [self.locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:(  @"purposeKey4changeInfo") completion:^(NSError * _Nonnull err) {
                // * @param completion 在弹框让用户选择后的用户的反馈,假如用户颁发该权限,block中的参数为nil,假如未颁发,block中的参数将为PurposeKey对于的key的描绘(如PurposeKey=TemporaryPurposKey_1)
// 先履行署理办法tencentLBSDidChangeAuthorization再履行此回调
                if(!err){//未颁发,则直接定位
                    [self requestLocation];
                }
            }];
            return ;
        }
    }
    // 2. 调用单次定位
    [self requestLocation];
}
- (void)requestLocation{
//    [self configLocationManager ];
    [self.locationManager requestLocationWithCompletionBlock:
        ^(TencentLBSLocation *location, NSError *error) {
            NSLog(@"%@, %@, %@", location.location, location.name, location.address);
        [SVProgressHUD dismiss];
        if(self.block){
            self.block(location,error);
        }
        }];
}
/**
 *  定位权限状况改动时回调函数
 *  @param manager 定位 TencentLBSLocationManager 类,由此拜访authorizationStatus,accuracyAuthorization
 */
- (void)tencentLBSDidChangeAuthorization:(TencentLBSLocationManager *)manager{
    //    - 假如定位精度权限变更为准确的时分,再次更新定位信息
    if (@available(iOS 14.0, *)) {
        if(    self.locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy){
            if(       self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey == YES){// 初次恳求
                self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey = NO;
                // 获取定位
                [self requestLocation];
            }
        }
    } else {
}
}

注意:仅当TencentLBSRequestLevel为TencentLBSRequestLevelPoi有回来值,否则为空。

/**
 *  回来当时方位周围的POI
 *  仅当TencentLBSRequestLevel为TencentLBSRequestLevelPoi有回来值,否则为空
 */
@property (nonatomic, strong, nullable) NSArray<TencentLBSPoi*> *poiList;

过错信息

typedef NS_ENUM(NSUInteger, TencentLBSLocationError) {
    TencentLBSLocationErrorUnknown = 0,                 //!< 过错码,表明现在方位不知道,可是会一直测验获取
    TencentLBSLocationErrorDenied = 1,                  //!< 过错码,表明定位权限被禁止
    TencentLBSLocationErrorNetwork = 2,                 //!< 过错码,表明网络过错
    TencentLBSLocationErrorHeadingFailure = 3,          //!< 过错码,表明朝向无法承认
    TencentLBSLocationErrorOther = 4,                   //!< 过错码,表明不知道过错
};

1.2 高德SDK

  1. 增加依赖 pod 'AMapLocation', '2.6.7'
  2. 导入头文件:“
- (void)setuprequestLocationWithAMapLocatingCompletionBlock:(AMapLocatingCompletionBlock)completionBlock{
    self.block =completionBlock;
    self.location = [[AMapLocationManager alloc]init];
    self.location.delegate = self;
    [SVProgressHUD showWithStatus:@"定位中.."];
    if (@available(iOS 14.0, *)) {
        self.location.locationAccuracyMode = AMapLocationFullAndReduceAccuracy;
    } else {
        // Fallback on earlier versions
    }
    [self.location setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
    //   定位超时时刻,最低2s,此处设置为2s
    self.location.locationTimeout = 2;
    //   逆地舆恳求超时时刻,最低2s,此处设置为2s
    self.location.reGeocodeTimeout = 2;
    [self.location requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
            [SVProgressHUD dismiss];
        if(completionBlock){
            completionBlock(location,regeocode,error);
        }
    }];
}

过错信息分析

///AMapLocation errorCode
typedef NS_ENUM(NSInteger, AMapLocationErrorCode)
{
    AMapLocationErrorUnknown = 1,               ///<不知道过错
    AMapLocationErrorLocateFailed = 2,          ///<定位过错
    AMapLocationErrorReGeocodeFailed  = 3,      ///<逆地舆过错
    AMapLocationErrorTimeOut = 4,               ///<超时
    AMapLocationErrorCanceled = 5,              ///<取消
    AMapLocationErrorCannotFindHost = 6,        ///<找不到主机
    AMapLocationErrorBadURL = 7,                ///<URL反常
    AMapLocationErrorNotConnectedToInternet = 8,///<连接反常
    AMapLocationErrorCannotConnectToHost = 9,   ///<服务器连接失利
    AMapLocationErrorRegionMonitoringFailure=10,///<地舆围栏过错
    AMapLocationErrorRiskOfFakeLocation = 11,   ///<存在虚拟定位风险
    AMapLocationErrorNoFullAccuracyAuth = 12,   ///<准确定位权限反常
};

II 判别经纬度是否在国内

2.1 判别经纬度是否在国内

TencentLBSLocationUtils
/**
 *  判别经纬度是否在国内
 *  
 */
+ (BOOL) isInRegionWithLatitude:(double)latitude longitude:(double)longitude;

blog.csdn.net/z929118967/…

封装


/**
 根据经纬度判别 是否在大陆地区
 */
+ (BOOL)inChineseMainlandWithCLLocation:(CLLocation *)location province:(NSString *)province{
    //coordinate.longitude
    if([TencentLBSLocationUtils isInRegionWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude]){
        // 扫除 香港、澳门、台湾
        if([province isEqualToString:@"香港特别行政区"] || [province isEqualToString:@"澳门特别行政区"] || [province isEqualToString:@"台湾"]){
            return NO;
        }else{
            return YES;
        }
    }else{//其他地区
        return NO;
    }
    return YES;
}

2.2 根据定位回来信息判别当时方位的行政区

/**
 *  回来当时方位的行政区划, 0-表明中国大陆、港、澳, 1-表明其他
 */
@property (nonatomic, assign) NSInteger areaStat;

III 封装定位SDK,一致数据模型

为了便于灵敏切换,新增定位一致进口,用于封装腾讯SDK和高德SDK,便于灵敏切换。

        [CRMLBSManager singleLocationIsShowError:YES WithcompletionBlock:^(CRMLBSLocationModel * _Nonnull location) {
            if(location.error){
                return;
            }
            if(!location.isInRegion){
                [SVProgressHUD showInfoWithStatus:@"您最新定位不在支撑范围内!"];
                return;
            }            
                    weakSelf.locationView.adressLab.text = location.address;
        }];
    }];

3.1 定位数据模型

@interface CRMLBSLocationModel : NSObject
/**
 *  回来当时方位的CLLocation信息
 */
@property (nonatomic, strong) CLLocation *location;
/**
 是否在国内,扫除港、澳、台
 */
@property (nonatomic, assign) BOOL isInRegion;
/**
 *  回来当时方位的地址
 */
@property (nonatomic, copy, nullable) NSString *address;
/**
 *  回来当时方位的省份
 */
@property (nonatomic, copy, nullable) NSString *province;
/**
 *  回来当时方位的大街
 */
@property (nonatomic, copy, nullable) NSString *street;
/**
 *  回来当时方位的大街编码
 */
@property (nonatomic, copy, nullable) NSString *street_no;
///爱好点名称
@property (nonatomic, copy) NSString *POIName;
@property (nonatomic, strong) NSError  *error;
@end

3.2 封装腾讯SDK的定位数据

/**
 isShowError: 发生过错是否展示提示语
 completionBlock: 定位回调
 */
+ (void)singleLocationIsShowError:(BOOL)isShowError WithcompletionBlock:(void (^)(CRMLBSLocationModel * _Nonnull location))completionBlock{
    [ERPLBS.shareERPLBS SingleLocation:^(TencentLBSLocation * _Nullable location, NSError * _Nullable error) {
        if ([SVProgressHUD isVisible]) {
            [SVProgressHUD dismiss];
        }
        CRMLBSLocationModel *model = [CRMLBSLocationModel new];
        if(error){//TencentLBSLocationError
            NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
            if(isShowError){
                NSString *errorInfo = error.userInfo[@"NSLocalizedDescription"];
                errorInfo=errorInfo?errorInfo:@"定位失利请从头再试!";
                [SVProgressHUD showErrorWithStatus:errorInfo];
                //           [self showHUDMessage:errorInfo];
            }
            model.error = error;
            if(completionBlock){
                completionBlock(model);
            }
            return;
        }
        // 定位成功
        if (!location)
        {
            if(completionBlock){
                completionBlock(model);
            }
            return;
        }
        NSLog(@"location:%@", location);
        model.street = location.street;
        model.street_no = location.street_no;
        model.address= location.address;
        model.location = location.location;//经纬度
        model.POIName =[location.poiList.firstObject name];//[ERPLBS POInamebyArr:location.poiList]
        model.province = location.province;//
        // 判别是否在大陆 areaStat
        model.isInRegion= [ERPLBS inChineseMainlandWithCLLocation:location.location province:location.province];
        if(completionBlock){
            completionBlock(model);
        }
    }];
}

3.3 封装高德SDK的定位数据

+ (void)singleLocation4AMapIsShowError:(BOOL)isShowError WithcompletionBlock:(void (^)(CRMLBSLocationModel * _Nonnull location))completionBlock{
    [[ProjectMethod shareProjectMethod] SingleLocation:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
        if ([SVProgressHUD isVisible]) {
            [SVProgressHUD dismiss];
        }
        CRMLBSLocationModel *model = [CRMLBSLocationModel new];
        if(error){//AMapLocationErrorCode
            NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
            if(isShowError){
                NSString *errorInfo = error.userInfo[@"NSLocalizedDescription"];
                errorInfo=errorInfo?errorInfo:@"定位失利请从头再试!";
                [SVProgressHUD showErrorWithStatus:errorInfo];
                //           [self showHUDMessage:errorInfo];
            }
            model.error = error;
            if(completionBlock){
                completionBlock(model);
            }
            return;
        }
        // 定位成功
        if (!location)
        {
            if(completionBlock){
                completionBlock(model);
            }
            return;
        }
        NSLog(@"location:%@", location);
        if (!regeocode)
        {
            if(completionBlock){
            completionBlock(model);
        }
            return;
        }
        NSLog(@"reGeocode:%@", regeocode);
        // 判别是否在大陆
        model.isInRegion= [ERPAMapLocationTool inChineseMainlandWithCLLocation:location regeocode:regeocode];
        model.location = location;//经纬度
        model.street = regeocode.street;
        model.street_no = regeocode.number;
        model.address=[NSString stringWithFormat:@"%@%@%@%@%@",regeocode.province,regeocode.city,regeocode.district,regeocode.street,regeocode.POIName];
        //regeocode.formattedAddress;//
        model.POIName =regeocode.POIName;
        model.province = regeocode.province;//
        if(completionBlock){
            completionBlock(model);
        }
    }];
}

3.4 一致定位进口

#define k_TENCENTLBS NO// 控制定位类型
/**
 isShowError: 发生过错是否展示提示语
 completionBlock: 定位回调
 */
+ (void)singleLocationIsShowError:(BOOL)isShowError WithcompletionBlock:(void (^)(CRMLBSLocationModel * _Nonnull location))completionBlock{
    NSLog(@"一致定位进口");
    //
    if(!k_TENCENTLBS){
        // 调用高德SDK
        NSLog(@"调用高德SDK");
        [self singleLocation4AMapIsShowError:isShowError WithcompletionBlock:completionBlock];
        return;
    }
    NSLog(@"调用腾讯SDK");
}

see also

公众号:iOS逆向