iOS 学习之获取地理位置

当 App 需要用户的位置信息时,我们可以直接使用系统自带的 CoreLocation 来获取,这里把相应的逻辑代码封装一下。

首先,在 info.plist 中加入以下配置,注意权限说明一定要说明清楚,给用户解释清楚为什么要使用地理权限,否则有可能会有被拒风险。

1
2
3
4
5
6
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>需要通过您的地理位置信息获取您的城市的天气情况</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要通过您的地理位置信息获取您的城市的天气情况</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要通过您的地理位置信息获取您的城市的天气情况</string>

以下便是代码块,都写了注释,所以这里我也不做过多的解释说明。

WYLocation.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@interface WYLocationObj : NSObject
/** 国家 */
@property (nonatomic, copy) NSString *country;
/** 省 直辖市 */
@property (nonatomic, copy) NSString *administrativeArea;
/** 地级市 直辖市区 */
@property (nonatomic, copy) NSString *locality;
/** 县 区 */
@property (nonatomic, copy) NSString *subLocality;
/** 街道 */
@property (nonatomic, copy) NSString *thoroughfare;
/** 子街道 */
@property (nonatomic, copy) NSString *subThoroughfare;
/** 经度 */
@property (nonatomic, assign) CLLocationDegrees longitude;
/** 纬度 */
@property (nonatomic, assign) CLLocationDegrees latitude;
@end


#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

@protocol WYLocationDelegate <NSObject>

/** 代理方法 获取当前地理位置成功 如果代理方法和block同时实现会优先使用bolck回调 */
- (void)locationDidEndUpdatingLocation:(WYLocationObj *)locationObj;

/** 代理方法 获取地理位置失败 如果代理方法和block同时实现会优先使用bolck回调 */
- (void)locationdidFailWithError:(NSError *)failure;

@end


typedef void(^locationSuccessHandler)(WYLocationObj *locationObj);
typedef void(^locationFailureHandler)(NSError *error);

@interface WYLocation : NSObject

@property (nonatomic, weak) id<WYLocationDelegate> delegate;

/** 获取定位信息 */
@property (nonatomic, strong, readonly) WYLocationObj *locationObj;

/** 单利初始化方法 */
+ (instancetype)shardLocationManger;

/** 定位失败 跳转修改系统权限 */
- (void)requetModifySystemForPermissions;

/** 监测 是否拥有定位权限 */
- (BOOL)locationServicesEnabled;

/** 开始定位 */
- (void)beginUpdatingLocation;

/** 开始定位并且 block 回调 */
- (void)beginUpdatingLocationSuccess:(locationSuccessHandler)success
failure:(locationFailureHandler)failure;

@end

WYLocation.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
@interface WYLocation () <CLLocationManagerDelegate>
@property (nonatomic, strong) WYLocationObj *location;
@property (nonatomic, strong) CLLocationManager * locationManager;
@property (nonatomic, copy) locationSuccessHandler successHandler;
@property (nonatomic, copy) locationFailureHandler failureHandler;
@end

@implementation WYLocation

static id _instace = nil;
+ (instancetype)shardLocationManger{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super init];
});
return _instace;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
if (_instace == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
}
return _instace;
}

+ (id)copyWithZone:(struct _NSZone *)zone {
return _instace;
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
return _instace;
}

#pragma mark - 定位失败
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if (self.failureHandler) {
self.failureHandler(error);
} else
{
if ([self.delegate respondsToSelector:@selector(locationdidFailWithError:)]) {
[self.delegate locationdidFailWithError:error];
}
}
}


#pragma mark - Public
- (void)beginUpdatingLocation {
if ([self.locationManager respondsToSelector:@selector(startUpdatingLocation)]) {
[self.locationManager startUpdatingLocation];
}
[self.locationManager requestWhenInUseAuthorization];
}

- (void)beginUpdatingLocationSuccess:(locationSuccessHandler)success
failure:(locationFailureHandler)failure {
[self beginUpdatingLocation];
self.successHandler = success;
self.failureHandler = failure;
}

- (void)requetModifySystemForPermissions {
UIApplication *app = [UIApplication sharedApplication];
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([app canOpenURL:settingsURL]) {
[app openURL:settingsURL];
}
}

- (BOOL)locationServicesEnabled {
BOOL isLocation = [CLLocationManager locationServicesEnabled]; //是否开启定位服务
if (!isLocation) {
return NO;
} else
{
CLAuthorizationStatus locationStatus = [CLLocationManager authorizationStatus];
switch (locationStatus) {
case kCLAuthorizationStatusNotDetermined: return NO; break; // 未询问用户是否授权
case kCLAuthorizationStatusRestricted: return NO; break; // 未授权,例如家长控制
case kCLAuthorizationStatusDenied: return NO; break; // 未授权,用户拒绝造成的
case kCLAuthorizationStatusAuthorizedAlways: return YES; break; // 同意授权一直获取定位信息
case kCLAuthorizationStatusAuthorizedWhenInUse: return YES; break; // 同意授权在使用时获取定位信息
default: return NO; break;
}
}
}


#pragma mark - 定位成功
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *currentLocation = locations.lastObject;
self.location.longitude = currentLocation.coordinate.longitude;
self.location.latitude = currentLocation.coordinate.latitude;

//根据经纬度反向地理编译出地址信息
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count > 0)
{
CLPlacemark *placemark = placemarks.firstObject;
self.location.country = placemark.country;
self.location.administrativeArea = placemark.administrativeArea;
self.location.locality = !placemark.locality ? placemark.administrativeArea : placemark.locality;
self.location.subLocality = placemark.subLocality;
self.location.thoroughfare = placemark.thoroughfare;
self.location.subThoroughfare = placemark.subThoroughfare;
NSLog(@"city = %@, longitude = %lg, latitude = %lg", self.location.locality, self.location.longitude, self.location.latitude);

if (self.successHandler) {
self.successHandler(self.location);
} else
{
if ([self.delegate respondsToSelector:@selector(locationDidEndUpdatingLocation:)]) {
[self.delegate locationDidEndUpdatingLocation:self.location];
}
}
}
}];

[manager stopUpdatingLocation];
}


#pragma mark - setter and getter

- (WYLocationObj *)locationObj {
return self.location;
}

- (CLLocationManager *)locationManager {
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter = 1000;
}
return _locationManager;
}

- (WYLocationObj *)location {
if(!_location){
_location = [[WYLocationObj alloc]init];
}
return _location;
}
@end


@implementation WYLocationObj

@end