引言

iOS14新增了精确定位和模糊定位的概念,用户可以手动选择,模糊定位的误差约 500m 。可以根据实际功能判断是否可以接受用户选择模糊定位。


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

iOS14 授权弹窗新增的Precise的开关默认会选中精确位置。用户通过这个开关可以进行更改,当把这个值设为 On 时,地图上会显示精确位置;切换为Off时,将显示用户的大致位置。



iOS小技能:“模糊定位”权限下的兼容策略、处理首次定位_地理位置


I “模糊定位”权限下的兼容策略

pod 'AMapLocation', '2.6.7'

iOS小技能:“模糊定位”权限下的兼容策略、处理首次定位_地理位置_02 ​​​用户可以通过在 “隐私设置” 中设置来开启精确定位,但是若用户不愿意开启。这个时候,iOS14 在 CLLocationManager 新增两个方法用于向用户申请临时开启一次精确位置权限。​

iOS小技能:“模糊定位”权限下的兼容策略、处理首次定位_iOS_03

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小技能:“模糊定位”权限下的兼容策略、处理首次定位_ios_04


  • 定位SDK适配文档详情请见:

在iOS14之后的SDK新增的API iOS小技能:“模糊定位”权限下的兼容策略、处理首次定位_iOS_05

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);

}

}

}

see also

iOS小技能:图片上传(优化图片上传的权限检测,引导设置相机权限和相册权限。

  • 高德
  • 百度iOS_14_beta版适配说明