iOS CLLocationManager 地理定位

鉴于地理位置的获取是异步的,所以在获取地理位置信息之后再通知当前用户使用,就封装了下。

需要导入的头文件:

import <CoreLocation/CoreLocation.h>

涉及到的类

CCLocationCClocationManager

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];启动定位的执行。因为处于授权过程中,所以定位没有结果。导致第一次授权启动定位失败,下次定位没问题。为了解决这个问题。我们在授权状态变成可用状态才进行定位的。即这段代码

授权后定位.png


另外再次获取定位信息时只需要 [self.locationManager startUpdatingLocation];或者 [self startUpdateLocation];就可以了。

更新时间2018-11-27

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值