鉴于地理位置的获取是异步的,所以在获取地理位置信息之后再通知当前用户使用,就封装了下。
需要导入的头文件:
import <CoreLocation/CoreLocation.h>
涉及到的类
CCLocation
CClocationManager
CCLocationManager像个坐标的管理者。CCLocation可以理解为对坐标的一些信息的封装。
封装的文件
.h文件
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
/**
地理位置获取之后的回调block
@param isAuthorized 是否授权
@param coordinate 获取CLLocation的属性coordinate坐标信息,是个结构体,内部包含经纬度。当为kCLLocationCoordinate2DInvalid表示未定位
@param error 定位失败时返回的信息,成功时为nil
*/
typedef void(^LocationCallBackWithCoordinateBlock) (BOOL isAuthorized,CLLocationCoordinate2D coordinate , NSError * _Nullable error);
/**
地理位置获取之后的回调block
@param isAuthorized 是否授权
@param location 获取的CLLocation,失败时为nil
@param error 定位失败时返回的信息,成功时为nil
*/
typedef void(^LocationCallBackWithLocationBlock) (BOOL isAuthorized,CLLocation * _Nullable location , NSError * _Nullable error);
@interface RainLocationKit : NSObject
/**
请求对地理位置获取的授权
第一次创建kit对象时,会做授权操作,授权结束后我们会去做一次定位。但是授权结束后,不会再去做定位了。如果再想拿同一个对象获取获取定位信息,请使用开始定位来获取
*/
- (void)requestLocationAuthorized;
/**
开启地理位置获取,并且传递地理位置获取成功后的回调block
因为地理位置的获取是异步的,所以等拿到数据之后再上传
@param locationCallBack 地理位置获取成功后的回调
*/
- (void)startUpdateLocationWithCoordinateCompletion:(LocationCallBackWithCoordinateBlock) locationCallBack;
- (void)startUpdateLocationWithLocationCompletion:(LocationCallBackWithLocationBlock) locationCallBack;
/**
设置定位成功之后回调,通过回调获取数据
@param locationCallBack 回调block
*/
- (void)setLocationCallbackBlock:(LocationCallBackWithCoordinateBlock) locationCallBack;
- (void)setLocationWithLocationCallBackBlock:(LocationCallBackWithLocationBlock) locationCallBack;
/**
开始更新定位信息。当授权完成之后,仍然使用当前定位对象时,可以使用该方法更新定位数据
*/
- (void)startUpdateLocation;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "RainLocationKit.h"
@interface RainLocationKit()<CLLocationManagerDelegate>
@property (nonatomic, strong, readonly)CLLocationManager *locationManager;
@property (nonatomic, strong, readonly)CLLocation *location;
@property (nonatomic, copy)LocationCallBackWithCoordinateBlock locationCallbackBlock;
@property (nonatomic, copy)LocationCallBackWithLocationBlock locationWithLocationCallBackBlock;
@end
@implementation RainLocationKit
@synthesize locationManager = _locationManager;
@synthesize location = _location;
- (void)startUpdateLocationWithCoordinateCompletion:(LocationCallBackWithCoordinateBlock) locationCallBack {
self.locationCallbackBlock = locationCallBack;
[self requestLocationAuthorized];
}
- (void)startUpdateLocationWithLocationCompletion:(LocationCallBackWithLocationBlock) locationCallBack {
self.locationWithLocationCallBackBlock = locationCallBack;
[self requestLocationAuthorized];
}
- (void)startUpdateLocation {
if ([self canUseLocation]) {
[self.locationManager startUpdatingLocation];
}else {
if (self.locationCallbackBlock) {
self.locationCallbackBlock(NO, kCLLocationCoordinate2DInvalid, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(NO, nil, nil);
}
}
}
- (void)requestLocationAuthorized {
if ([CLLocationManager locationServicesEnabled]) {
if(@available(iOS 8.0,*)) {
[self.locationManager requestWhenInUseAuthorization];
}
}else {
#ifdef DEBUG
NSLog(@"地理位置服务不可用");
#endif
if (self.locationCallbackBlock) {
self.locationCallbackBlock(NO, kCLLocationCoordinate2DInvalid, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(NO, nil, nil);
}
}
}
/**
是否可以使用定位
即授权未拿到或者未定义plist文件里的授权描述
info.plist里需要定义的两个key-value信息如下:
<key>NSLocationAlwaysUsageDescription</key>
<string>我们将使用你的位置为你提供就近咨询和信息服务</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们将使用你的位置为你提供就近咨询和信息服务</string>
@return YES表示可以使用,NO表示不可以使用,
*/
- (BOOL)canUseLocation {
if (![CLLocationManager locationServicesEnabled]) {
return NO;
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways &&
[CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
return NO;
}
return YES;
}
#pragma mark- CLLocationManagerDelegate
/**
授权状态变更代理回调
@param manager 位置管理器
@param status 状态值
*/
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSString *message = nil;
switch (status) {
case kCLAuthorizationStatusAuthorizedAlways:
[self startUpdateLocation];
message = @"一直使用地理位置";
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self startUpdateLocation];
message = @"使用期间使用地理位置";
break;
case kCLAuthorizationStatusDenied:
message = @"用户禁用地理位置访问服务";
break;
case kCLAuthorizationStatusRestricted:
message = @"系统定位服务功能被限制";
break;
case kCLAuthorizationStatusNotDetermined:
message = @"用户未决定地理位置的使用";
break;
default:
break;
}
#ifdef DEBUG
NSLog(@"地理位置授权状态变化:%@", message);
#endif
}
/*
获取到了定位数据
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
_location = [locations lastObject];
#ifdef DEBUG
NSLog(@"经纬度可能会获取多次");
NSLog(@"纬度 = %f", _location.coordinate.latitude);
NSLog(@"经度 = %f", _location.coordinate.longitude);
#endif
[self.locationManager stopUpdatingLocation];
if (self.locationCallbackBlock) {
self.locationCallbackBlock(YES, _location.coordinate, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(YES, _location, nil);
}
}
/*
*定位失败
*/
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
#ifdef DEBUG
NSLog(@"定位失败 error: %@", [error description]);
#endif
if (self.locationCallbackBlock) {
self.locationCallbackBlock(YES, kCLLocationCoordinate2DInvalid, error);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(YES, nil, error);
}
}
#pragma mark- getter
- (CLLocationManager *)locationManager {
if (_locationManager == nil) {
_locationManager = CLLocationManager.new;
_locationManager.delegate = self;
///期望的精准度。有五个选项值。我们使用的是最好精度
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
///刷新距离
_locationManager.distanceFilter = 10;
}
return _locationManager;
}
- (void)setLocationCallbackBlock:(LocationCallBackWithCoordinateBlock) locationCallBack {
_locationCallbackBlock = locationCallBack;
}
- (void)setLocationWithLocationCallBackBlock:(LocationCallBackWithLocationBlock) locationCallBack {
_locationWithLocationCallBackBlock = locationCallBack;
}
@end
解释说明
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
这个方法里能获取到用户对地理位置信息的授权状态。但是授权过程并不会中断[self.locationManager startUpdatingLocation];
启动定位的执行。因为处于授权过程中,所以定位没有结果。导致第一次授权启动定位失败,下次定位没问题。为了解决这个问题。我们在授权状态变成可用状态才进行定位的。即这段代码
。
另外再次获取定位信息时只需要
[self.locationManager startUpdatingLocation];
或者[self startUpdateLocation];
就可以了。
网友评论