iOS开发-浅谈定位权限
[TOC]
在iOS8之后,关于权限信息有些更改
对于定位权限而言,相对其他的权限稍微麻烦一些
1、key的配置
1、使用app的时候使用位置信息
NSLocationWhenInUseUsageDescription
2、允许app一直使用位置信息
NSLocationAlwaysUsageDescription
3、允许2中选择同时存在
11.4之后有用
NSLocationAlwaysAndWhenInUseUsageDescription
2、api的调用
有2个api:
requestWhenInUseAuthorization //when-in-use
requestAlwaysAuthorization //Always
这2个api从表面来看,意思是请求when-in-use
或Always
但是实测发现when-in-use
完全可以覆盖Always
,也就是说Always
完全可以不用,让when-in-use
根据plist中的key配置自动去完成所需要的权限弹框。
具体测试如下:
1)、11.4系统以下(上面说到 alwayandwhen 对11.4以下无用,这里不测试)
配置信息 | requestWhenInUseAuthorization | requestAlwaysAuthorization |
---|---|---|
1 |
请求1 | 无效 |
2 |
请求2 | 请求2 |
1 2
|
请求2 | 请求2 |
2)、11.4系统以后
配置信息 | requestWhenInUseAuthorization | requestAlwaysAuthorization |
---|---|---|
1 |
请求1 | 无效 |
2 |
无效 | 无效 |
3 |
无效 | 无效 |
1 2
|
请求1 | 无效 |
1 3
|
请求1、2 | 请求1、2 |
1 2 3
|
请求1、2 | 请求1、2 |
基于以上测试结果, 我们可以发现:
11.4之前的系统:
1
、2
可以单独存在。
11.4之后的系统:
所有的权限必须基于1
而存在。
在app开发中,现在一般最低适配的系统是8或者9,所以在plist中配置key的时候,1
是必须的,如果需要用到一直使用位置权限,那么1
2
3
3个key都需要配置
3、权限请求
对于app中权限的请求,相册、相机等都有系统提供的api直接去请求权限,但是位置信息比较麻烦,在这里做了一个封装:
具体代码如下:
JEAuthorityTool.h
文件
引入系统库 #import <CoreLocation/CoreLocation.h>
/**
请求定位权限
@param block 结果
*/
+(void)je_authorityLocationRequest:(void(^)(BOOL granted,
CLAuthorizationStatus status))block;
/**
* 获取定位使用权限
*
* @param location BOOL 表示系统所有app有没有打开定位 status app的定位权限状态
*/
+(void)je_authorityLocation:(void(^)(BOOL canLocation ,
CLAuthorizationStatus status))location;
JEAuthorityTool.m
文件
#import "JEAuthorityTool.h"
typedef void(^je_authorityLocationBLock)(BOOL granted,CLAuthorizationStatus state);
@interface JEAuthorityTool ()<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (copy, nonatomic) je_authorityLocationBLock locationBlock;
@end
static dispatch_once_t onceToken;
+ (JEAuthorityTool *)sharedLocationManage
{
static JEAuthorityTool *__singletion;
dispatch_once(&onceToken, ^{
__singletion=[[self alloc] init];
});
return __singletion;
}
-(instancetype)init
{
if (self = [super init])
{
self.locationManager = [CLLocationManager new];
}
return self;
}
+(void)je_authorityLocationRequest:(void(^)(BOOL granted,
CLAuthorizationStatus status))block
{
[self sharedLocationManage].locationBlock = block;
BOOL canUser;
CLAuthorizationStatus status;
[self je_authorityLocation:&canUser status:&status];
if (status == kCLAuthorizationStatusNotDetermined)
{
CLLocationManager *manager = [self sharedLocationManage].locationManager;
manager.delegate = [self sharedLocationManage];
[manager requestWhenInUseAuthorization];
NSDictionary *dic = [NSBundle mainBundle].infoDictionary;
BOOL boolWhen = locationContentWithStr(@"NSLocationWhenInUseUsageDescription",dic);
BOOL boolAlway = locationContentWithStr(@"NSLocationAlwaysUsageDescription",dic);
BOOL show = NO;
if (@available(iOS 11.4, *))
show = boolWhen;
else
show = (boolAlway || boolWhen);
if (!show) {
NSLog(@"---------------------\n\
⚠️如果第一次没有弹出权限请求\n\
请在plist中配置位置权限信息\n\
按照实际需求,需要配置以下key\n\
NSLocationWhenInUseUsageDescription 和\n\
NSLocationAlwaysUsageDescription 和\n\
NSLocationAlwaysAndWhenInUseUsageDescription\n\
---------------------");
}
}
else{
if ([self sharedLocationManage].locationBlock)
{
[self sharedLocationManage].locationBlock(canUser, status);
[self sharedLocationManage].locationBlock = nil;
}
[self sharedLocationManage].locationManager = nil;
onceToken = 0;
}
}
BOOL locationContentWithStr(NSString *str, NSDictionary *dic)
{
if ([[dic allKeys] containsObject:str])
{
id value = dic[str];
if ([value isKindOfClass:[NSString class]])
{
return YES;
}
}
return NO;
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status != kCLAuthorizationStatusNotDetermined)
{
if (self.locationBlock) {
self.locationBlock([[self class] je_authorityBoolLocation ], status);
self.locationBlock = nil;
}
self.locationManager = nil;
onceToken = 0;
}
}
+(void)je_authorityLocation:(void (^)(BOOL, CLAuthorizationStatus))location
{
if (location) {
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"系统所有app都没有打开定位功能");
location(NO,kCLAuthorizationStatusDenied);
return;
}
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
location(YES,status);
}
}
+(void)je_authorityLocation:(BOOL *)systemOpen status:(CLAuthorizationStatus *)status
{
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"系统所有app都没有打开定位功能");
*systemOpen = NO;
*status = kCLAuthorizationStatusDenied;
}
else
{
*systemOpen = YES;
*status = [CLLocationManager authorizationStatus];
}
}
+(BOOL)je_authorityBoolLocation
{
BOOL systemOpen;
CLAuthorizationStatus status;
[self je_authorityLocation:&systemOpen status:&status];
if (systemOpen == NO) {
return NO;
}
else
{
if (status == kCLAuthorizationStatusNotDetermined ||
status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusAuthorizedWhenInUse)
{
return YES;
}
else{
return NO;
}
}
}
修改补充:
(2018-10-30)
1、2楼的兄弟提到Privacy - Location Usage Description(NSLocationUsageDescription),这个是iOS6-8的时候才使用的一个位置权限配置key,iOS8以后就舍弃了这个,因为在8之前,没有“使用时定位”和“一直定位”的区分。
如果要适配8之前的系统,如果能加的话还是要加上(我目前的项目都是最低适配8,而且模拟器最低也只能下到8.1的版本,所以无法测试)。参考链接(在页面内搜索NSLocationUsageDescription)