授权状态
.Restricted 表示GPS功能受限于某些限制,无法使用定位服务,例如parental controls
kCLAuthorizationStatusNotDetermined //用户没有选择是否要使用定位服务(弹框没选择,或者根本没有弹框
kCLAuthorizationStatusRestricted //定位服务授权状态受限制,可能由于活动限制了定位服务,并且用户不能改变当前的权限,这个状态有可能不是用户拒绝的,但是也有可能是用户拒绝的。官网说的,具体没遇到过(遇到过的童鞋请告知谢谢)
kCLAuthorizationStatusDenied //用户在设置中关闭定位功能,或者用户明确的在弹框之后选择禁止定位
kCLAuthorizationStatusAuthorized //用户已经明确使用定位功能
kCLAuthorizationStatusAuthorizedWhenInUse //用户在使用期间允许使用定位功能
kCLAuthorizationStatusAuthorizedAlways //App始终允许使用定位功能
1.iOS8以前使用CLLocationManager
- 1.导入头文件
<CoreLocation/CoreLocation.h>
- 2.创建位置管理者
CLLocationManager
, 并添加到属性。 - 3.设置代理、遵守协议、实现代理方法,在代理方法中获取位置信息
- 4.调用开始更新位置方法
- 5.设置
每隔多远定位一次
和精确度
,精确度越高越耗电,定位时间越长
// 1.设置位置管理者属性
@property (nonatomic, strong) CLLocationManager *lcManager;
// 2.判断是否打开了位置服务
if ([CLLocationManager locationServicesEnabled]) {
// 创建位置管理者对象
self.lcManager = [[CLLocationManager alloc] init];
self.lcManager.delegate = self; // 设置代理
// 设置定位距离过滤参数 (当本次定位和上次定位之间的距离大于或等于这个值时,调用代理方法)
self.lcManager.distanceFilter = 100;
self.lcManager.desiredAccuracy = kCLLocationAccuracyBest; // 设置定位精度(精度越高越耗电)
[self.lcManager startUpdatingLocation]; // 开始更新位置
}
/** 获取到新的位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"定位到了");
}
/** 不能获取位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"获取定位失败");
}
- 6.请求授权,iOS6之后,苹果开始加强保护用户隐私,在
Info.plist
文件中定义Key
提醒用户,提高用户允许定位的概率。
image.png -
7.如果要后台定位,需要打开后台模式
Snip20200731_1.png
2.iOS8.0之后使用CLLocationManager
- 1.iOS8之后,苹果又进一步加强了隐私保护,不会主动填出对话框,让用户选择
- 2.需要实现两个方法(实现其一即可),并且
Info.plist
中设置对应的key
,才会弹框
1.requestWhenInUseAuthorization
- 1.当程序当前的授权状态为未决定时,在前台时请求定位服务许可时使用。需要先在 Info.plist 文件中设置一个
Key:NSLocationWhenInUseUsageDescription
, 如果不设置key,系统会忽略定位请求。
- 2.当用户授权
when-in-use
时,程序在前台时可以启动大部分定位服务。如果想要后台定位,需要开启后台定位模式,但在状态栏会出现蓝条提示用户程序正在进行定位。
[_lcManager requestWhenInUseAuthorization];
Snip20200731_4.png
iOS 后台定位 蓝条问题
image.png蓝条问题的产生机理和处理办法:
CLLocationManager管理类的配置
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.distanceFilter = 100;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if ([[UIDevice currentDevice] systemVersion].floatValue >= 8) {
/*
有这么一种说法
如果两个请求授权的方法都执行了,会出现以下情况
1.requestWhenInUseAuthorization写在前面,第一次打开程序时请求授权,如果勾选了后台模式,进入后台会出现蓝条提示正在定位。当程序退出,第二次打开程序时requestAlwaysAuthorization 会再次请求授权。之后进入后台就不会出现蓝色状态栏。
2.requestAlwaysAuthorization写在前面, requestWhenInUseAuthorization写在后面,只会在第一次打开程序时请求授权,因为requestAlwaysAuthorization得到的授权大于requestWhenInUseAuthorization得到的授权
*/
[_locationManager requestAlwaysAuthorization];
[_locationManager requestWhenInUseAuthorization];
}
if ([[UIDevice currentDevice] systemVersion].floatValue >= 9) {
/*
allowsBackgroundLocationUpdates:是否允许后台定位,默认为NO,只在iOS9.0之后起作用。
设为YES时,必须保证Background Modes 中的Location updates处于选中状态,否则会抛出异常。
在用户选择仅在使用应用期间获取位置权限的情况下,当应用进入后台,手机桌面顶部是否出现蓝条,这句代码起着关键性作用。
首先,这句代码仅在requestWhenInUseAuthorization状态下才起作用,否则不起作用。当设为YES,就是允许在requestWhenInUseAuthorization此状态下,即使App进入后台,但是没杀死,那么就依然可以后台定位。并且顶部给个蓝条闪烁,目的是在于实时提醒用户:你这个App一直在获取你的位置信息哟,如果你感到不需要继续获取了,就杀死该App吧!所以一直蓝条闪烁。
当设置为NO,就是在requestWhenInUseAuthorization状态下,App进入后台,立即停止后台定位。
*/
_locationManager.allowsBackgroundLocationUpdates = YES;
/*
requestLocation和startUpdatingLocation这两个方法非常类似,都会立即返回结果,将获取的定位信息传递给委托对象的locationManager:didUpdateLocations:消息。
不同点:
startUpdatingLocation:可以持续获取定位。当设备移动的距离超过设定的distanceFilter属性值时,接收器会再次生成一条更新消息。
requestLocation:只产生一次定位信息,在此之后定位服务就停止了。并且:当使用这个方法时,委托对象必须要实现locationManager:didUpdateLocations:和locationManager:didFailWithError:方法。
*/
[_locationManager requestLocation];
} else {
[_locationManager startUpdatingLocation];
}
其实在上段代码注释中已经写得较清楚了。
蓝条问题的产生前提:只在requestWhenInUseAuthorization这个状态下才会出现。
蓝条出现的目的:因为用户选择的是仅在应用使用期间获取位置,所以当app进入后台后,系统将以蓝条闪烁的形式不断提醒用户:主人,某某App一直在后台获取你的位置权限哟,如果你不需要用到了,你就直接将该App杀死吧,不然挺耗电的,如果有需要就当我没说哈。
蓝条出现与否的背后代码操控者:_locationManager.allowsBackgroundLocationUpdates = YES
;如果不想出现蓝条,直接设置为NO,或者注释,因为默认为NO。
另外,蓝条出现与否的另一种说法:跟下面两句代码的执行顺序有关
[_locationManager requestAlwaysAuthorization];
[_locationManager requestWhenInUseAuthorization];
2.requestAlwaysAuthorization
- 1.请求前后台定位服务授权,当授权状态为未决定时请求用户授权。前提是在 Info.plist 文件中包含key
NSLocationAlwaysUsageDescription
这边为什么还是显示的User的文档呢?
因为:在ios11中,NSLocationAlwaysUsageDeion
被当做NSLocationWhenInUseUsageDeion
来处理了
在IOS11,原有的NSLocationAlwaysUsageDeion被降级为NSLocationWhenInUseUsageDeion。因此,在原来项目中使用requestAlwaysAuthorization获取定位权限,而未在plist文件中配置NSLocationAlwaysAndWhenInUseUsageDeion,系统框不会弹出。建议新旧key值都在plist里配置,反正我试下来是没有问题,唯一的区别是使用requestAlwaysAuthorization获取权限 IOS11系统弹框会把几种权限级别全部列出,供用户选择,显然更人性化了哈~~
在plist文件中如果不包含“ NSLocationAlwaysAndWhenInUseUsageDeion”
会报:The app's Info.plist must contain both “NSLocationAlwaysAndWhenInUseUsageDescription” and “NSLocationWhenInUseUsageDescription” keys with string values explaining to the user how the app uses this data
这个错误
还有一种情况:
截屏2020-07-31 下午5.28.59.png当你第一次用requestWhenInUseAuthorization
请求了
会弹出
如果第二次用“requestAlwaysAuthorization”请求,就会弹出
image.png
这边的文案显示的plist中配置的 NSLocationAlwaysAndWhenInUseUsageDeion
的文案
说明弹出这个,必须在plist中配置NSLocationAlwaysAndWhenInUseUsageDeion
3.注意
-
1.iOS8之后,如果想要定位,必须调用
requestWhenInUseAuthorization
或requestAlwaysAuthorization
方法。 -
2.如果两个请求授权的方法都执行了,会出现以下情况
-
1.
when-in-use
写在前面,第一次打开程序时请求授权,如果勾选了后台模式,进入后台会出现蓝条提示正在定位。当程序退出,第二次打开程序时Always
会再次请求授权。之后进入后台就不会出现蓝条了(前后台都能定位) -
2.
Always
写在前面,when-in-use
写在后面,只会在第一次打开程序时请求授权,因为Always
得到的授权大于when-in-use
的到的授权
-
4.判断是否开启了定位服务
- 在启动更新位置之前要先判断是否开启了定位服务
if ([CLLocationManager locationServicesEnabled]) { // 判断是否打开了位置服务
[self.lcManager startUpdatingLocation]; // 开始更新位置
}
5.适配版本号的方法
-
when-in-use
和Always
都是iOS8之后出现的方法,如果不进行版本适配,运行在iOS7上就会crash,此时需要做版本号判断 -
1.判断版本号
if ([[UIDevice currentDevice].systemVersion floatValue] >=8.0 ) {
[_lcManager requestAlwaysAuthorization];
}
- 2.适配版本的另一种方法
if ([_lcManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_lcManager requestWhenInUseAuthorization];
}
6.监听定位服务状态的改变
- 实现代理方法,判断定位服务的状态
/** 定位服务状态改变时调用*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定授权");
break;
}
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
break;
}
case kCLAuthorizationStatusDenied:
{
// 类方法,判断是否开启定位服务
if ([CLLocationManager locationServicesEnabled]) {
NSLog(@"定位服务开启,被拒绝");
} else {
NSLog(@"定位服务关闭,不可用");
}
break;
}
case kCLAuthorizationStatusAuthorizedAlways:
{
NSLog(@"获得前后台授权");
break;
}
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"获得前台授权");
break;
}
default:
break;
}
}
7.代理方法返回的 locations
信息
-
当位置管理器,获取到位置后,调用
locationManager:didUpdateLocations:
方法,返回的类型为CLLocation
的位置信息数组,以下为数组包含的属性 -
1.coordinate : 当前位置的坐标
*latitude : 纬度
*longitude : 经度 -
2.altitude : 海拔,高度
-
3.horizontalAccuracy : 纬度和经度的精度
-
4.verticalAccuracy : 垂直精度(获取不到海拔时为负数)
-
5.course : 行进方向(真北)
-
6.speed : 以米/秒为单位的速度
-
7.description : 位置描述信息
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations firstObject];
NSLog(@"%@", location);
}
3.iOS9.0之后使用CLLocationManager
-
1.iOS9.0之后有一种新的请求定位的方法
requestLocation
-
2.作用:按照定位精确度从低到高进行排序,逐个进行定位。如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界。
-
3.注意:
-
1.必须实现
ocationManager:didUpdateLocations:
和locationManager:didFailWithError
方法,但是只调用一次 -
2.不能与
startUpdatingLocation
同时使用
if ([CLLocationManager locationServicesEnabled]) { // 判断是否打开了位置服务
[self.lcManager requestLocation];
}
- 4.实现
requestWhenInUseAuthorization
或requestAlwaysAuthorization
方法,并设置对应的key
if ([[UIDevice currentDevice].systemVersion floatValue] >=8.0 ) {
// iOS0.0:如果当前的授权状态是使用是授权,那么App退到后台后,将不能获取用户位置,即使勾选后台模式:location
[_lcManager requestWhenInUseAuthorization];
}
-
5.必须勾选后台模式,并设置
allowsBackgroundLocationUpdates
属性为YES(默认是NO) -
1.当定位完成时,设置为NO,并且不再定位跟踪
-
2.使用
-responsdToSelector:
判断
// iOS9.0+ 要想继续获取位置,需要使用以下属性进行设置(注意勾选后台模式:location)但会出现蓝条
if ([_lcManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
_lcManager.allowsBackgroundLocationUpdates = YES;
}
网友评论