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

引言

iOS14新增了准确定位和含糊定位的概念,用户能够手动挑选,含糊定位的误差约 500m 。能够根据实践功用判别是否能够承受用户挑选含糊定位。

iOS14新增用户大致方位选项可供用户挑选的原因是大多数 App 实践上并不需求获取用户到用户最准确的定位信息。

iOS14 授权弹窗新增的Precise的开关默许会选中准确方位。用户经过这个开关能够进行更改,当把这个值设为 On 时,地图上会显现准确方位;切换为Off时,将显现用户的大致方位。

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

使用场景:

  1. 商户进件的运营地址定位(商户概况的重新定位、进件信息编辑时的商户地址定位)

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内
iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

  1. 付出设备终端的定位信息更新

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

I 含糊定位适配

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内
用户能够经过在 “隐私设置” 中设置来敞开准确定位,但是若用户不愿意敞开。这个时分,iOS14 在 CLLocationManager 新增两个办法用于向用户恳求暂时敞开一次准确方位权限。

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

1.1 plist装备

NSLocationTemporaryUsageDescriptionDictionary

    <key>NSLocationTemporaryUsageDescriptionDictionary</key>
     <dict>
     <key>purposeKey4changeInfo</key>
     <string>此app需求准确的定位信息,以便于更好的为你服务. </string>
    </dict>

1.2 设置 locationAccuracyMode

locationAccuracyMode设置为AMapLocationFullAndReduceAccuracy/AMapLocationFullAccuracy

    if (@available(iOS 14.0, *)) {
        self.location.locationAccuracyMode = AMapLocationFullAndReduceAccuracy;
    } else {
        // Fallback on earlier versions
    }

1.3 完成署理办法

/**
 *  @brief 当plist装备NSLocationTemporaryUsageDescriptionDictionary且desiredAccuracyMode设置CLAccuracyAuthorizationFullAccuracy准确定位模式时,假如用户只授权含糊定位,会调用署理的此办法。此办法完成调用恳求暂时准确定位权限API即可:
 *  [manager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"PurposeKey" completion:^(NSError *error){
 *     if(completion){
 *        completion(error);
 *     }
 *  }]; (有必要调用,不然无法正常获取暂时准确定位权限)
 *  @param manager 定位 AMapLocationManager 类。
 *  @param locationManager 需求恳求暂时准确定位权限的locationManager。
 *  @param completion 暂时准确定位权限API回调结果,error: 直接回来体系error即可。
 *  @since 2.6.7
 */
- (void)amapLocationManager:(AMapLocationManager *)manager doRequireTemporaryFullAccuracyAuth:(CLLocationManager*)locationManager completion:(void(^)(NSError *error))completion;
{
   if(@available(iOS 14.0,*)){
       [locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"purposeKey4changeInfo" completion:^(NSError * _Nullable error) {
          if(completion){
             completion(error);
          }
      }];
   }
}

1.4 处理定位权限状况改动的回调函数

假如定位精度权限改动为准确的时分,再次更新定位信息

/**
 记载当时是否向用户恳求暂时敞开一次准确方位权限,用于【假如定位精度权限改动为准确的时分,再次更新定位信息】
 */
@property (assign, nonatomic) BOOL isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey;
/**
 存储获取定位信息的回调
 */
@property (nonatomic, copy) AMapLocatingCompletionBlock block;
/**
 *  @brief 定位权限状况改动时回调函数。留意:iOS14及之后版本回调
 *  @param manager 定位 AMapLocationManager 类。
 *  @param locationManager  定位CLLocationManager类,可经过locationManager.authorizationStatus获取定位权限,经过locationManager.accuracyAuthorization获取定位精度权限
 */
- (void)amapLocationManager:(AMapLocationManager *)manager locationManagerDidChangeAuthorization:(CLLocationManager*)locationManager{
    //
//    - 假如定位精度权限改动为准确的时分,再次更新定位信息
    if (@available(iOS 14.0, *)) {
        if(    locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy){
            if(       self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey == YES){
                self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey = NO;
                [self.location requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
                    [SVProgressHUD dismiss];
                    if(self.block){
                        self.block(location,regeocode,error);
                    }
                }];
            }
        }
    } else {
        // Fallback on earlier versions
    }
}
  • 效果

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

  • 定位SDK适配文档概况请见:

在iOS14之后的SDK新增的API

iOS小技能:模糊定位适配、处理首次定位引导授权、判断经纬度是否在国内

II 引导用户授权,并监听状况改动。

定位之前,先检测权限,假如是初次安装app,第一次运用定位时,调用requestAlwaysAuthorization恳求定位权限,引导用户授权,并监听状况改动。

不引荐运用高德SDK的API处理,引荐定位之前运用原生API自己处理,这样也方便今后切换腾讯SDK。

2.1 运用高德SDK的API处理(不引荐)

检测状况

    if(![QCTLocationServiceUtil isHasLocationAuthorityWithisShowAlert:YES]){
        return ;
    }
    [self setuprequestLocationWithAMapLocatingCompletionBlock:completionBlock];

引导用户授权

- (void)amapLocationManager:(AMapLocationManager *)manager doRequireLocationAuth:(CLLocationManager*)locationManager
{
//    locationManager.delegate = self;// 设置署理将无回调requestLocationWithReGeocode
    // 判别kCLAuthorizationStatusNotDetermined时设置isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey
    self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey = YES;// 区别初次运用
    [locationManager requestAlwaysAuthorization];
}

监听状况改动

- (void)amapLocationManager:(AMapLocationManager *)manager locationManagerDidChangeAuthorization:(CLLocationManager*)locationManager{
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    NSLog(@"amapLocationManager locationManagerDidChangeAuthorization:%d",status);
//    - 假如定位精度权限改动为准确的时分,再次更新定位信息
    if (@available(iOS 14.0, *)) {
        if(    locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy){
            if(       self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey == YES){// 初次恳求
                self.isrequestTemporaryFullAccuracyAuthorizationWithPurposeKey = NO;
                [self.location requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
                    [SVProgressHUD dismiss];
                    if(self.block){
                        self.block(location,regeocode,error);
                    }
                }];
            }
        }
    } else {
        // Fallback on earlier versions
    }
}

2.2 原生API处理初次定位(引荐)

检测定位权限

    __weak __typeof__(self) weakSelf = self;
    [QCTLocationServiceUtil isHasLocationAuthorityWithisShowAlert:YES block:^(id  _Nonnull sender) {
        [weakSelf setuprequestLocationWithAMapLocatingCompletionBlock:completionBlock];// 恳求定位
    }];

封装定位权限检查


+(BOOL)isHasLocationAuthorityWithisShowAlert:(BOOL)showAlert block:(void (^)(id sender))block {
    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){//用户没有对该使用程序作出挑选,安装之后第一次运用
//        CLLocationManager *manager = [[CLLocationManager alloc] init];
        CLLocationManager *manager = ProjectMethod.shareProjectMethod.locationManager;
        ProjectMethod.shareProjectMethod.block4location = block;// 监听状况改动时,履行的block
        [manager requestAlwaysAuthorization];
//
        return NO;
    }
    NSLog(@" 获取方位权限正常==============");
    if(block){// 3. 履行允许之后的定位操作
        block(nil);
    }
    return YES;
}

监听状况改动

- (CLLocationManager *)locationManager{
    if(_locationManager == nil){
        _locationManager = [CLLocationManager new];
        _locationManager.delegate = self;
    }
    return _locationManager;
}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager API_AVAILABLE(ios(14.0), macos(11.0), watchos(7.0), tvos(14.0)){
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    NSLog(@"locationManagerDidChangeAuthorization:%d",status);
    if(status ==kCLAuthorizationStatusAuthorizedAlways|| status == kCLAuthorizationStatusAuthorizedWhenInUse){// 3 ||4
        if(self.block4location){
            self.block4location(nil);
        }
    }
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_DEPRECATED_WITH_REPLACEMENT("-locationManagerDidChangeAuthorization:", ios(4.2, 14.0), macos(10.7, 11.0), watchos(1.0, 7.0), tvos(9.0, 14.0)){
//    nsl
    //kCLAuthorizationStatusAuthorizedAlways
//    kCLAuthorizationStatusAuthorizedWhenInUse
    if(status ==kCLAuthorizationStatusAuthorizedAlways|| status == kCLAuthorizationStatusAuthorizedWhenInUse){//3 ||4
        if(self.block4location){
            self.block4location(nil);
        }
    }
}

III 单次定位

定位SDK引荐挑选腾讯,因为高德的反地舆编码库不准确(没有实时更新)

3.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 {
}
}

3.2 高德SDK

  pod 'AMapLocation', '2.6.7'
- (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);
        }
    }];
}

IV 判别经纬度是否在国内

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(AMapLocationDataAvailableForCoordinate(location.coordinate)){//当时方位在大陆、港澳地区
        //香港特别行政区
//        澳门特别行政区
        /////省/直辖市
//        @property (nonatomic, copy) NSString *province;
        if([province isEqualToString:@"香港特别行政区"] || [province isEqualToString:@"澳门特别行政区"]){
            return NO;
        }else{
            return YES;
        }
    }else{//其他地区
        return NO;
    }
    return YES;
}

see also

iOS小技术:图片上传(优化图片上传的权限检测,引导设置相机权限和相册权限。)https://blog.csdn.net/z929118967/article/details/103819800

  • 高德

  • 百度iOS_14_beta版适配说明