1 // ViewController.m
2 // CoreLocation框架的基本使用—定位
3 // 注意 点: 1.设置地位可用 2. 设置允许本程序定位(对弹出的框,允许即可) 3. 为模拟器 设置位置移动方式, 比如 Freeway Drive(自由驾车模式)
4
5
6 #import "ViewController.h"
7 #import <CoreLocation/CoreLocation.h>
8
9 #define isIOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version)
10
11 @interface ViewController ()<CLLocationManagerDelegate>
12 {
13 CLLocation *_lastLoc;
14 }
15 /** 位置管理者*/
16 @property (nonatomic, strong) CLLocationManager *locM;
17
18 @end
19
20 @implementation ViewController
21
22 #pragma mark - 懒加载
23 /** locM属性的懒加载 */
24 -(CLLocationManager *)locM
25 {
26 if (!_locM) {
27 // 1. 创建位置管理者
28 _locM = [[CLLocationManager alloc] init];
29 // 1.1 block , 代理, 通知
30 _locM.delegate = self;
31
32 // 精确度越高, 越好点, 而且, 定位时间越长
33 // 精确度
34 _locM.desiredAccuracy = kCLLocationAccuracyBest;
35
36
37 /** ----------iOS8.0+定位适配-------------- */
38
39 // 如果两个授权请求,同时发送, 那么先执行第一个
40
41 if(isIOS(8.0))
42 {
43
44 // 请求前后台定位授权
45 // 无论是在前台还是后台, 都可以获取用户位置,而且不会出现蓝条
46 // 无论是否勾选后台模式
47 // 如果当前的授权状态 != 用户未选择状态, 那么这个方法不会有效
48 // 如果当前授权状态 == 前台定位授权时, 这个方法也会有效
49 // [_locM requestAlwaysAuthorization];
50
51
52 // 请求前台定位授权
53 // 在前台授权下, 默认只能在前台获取用户位置信息, 如果想要在后台获取用户位置, 那么 勾选后台模式 Location updates (会出现蓝条)
54 // 如果当前的授权状态 != 用户未选择状态, 那么这个方法不会有效
55 [_locM requestWhenInUseAuthorization];
56
57
58 // 在前台授权下, 默认只能在前台获取用户位置信息, 如果想要在后台获取用户位置, 那么 勾选后台模式 Location updates (会出现蓝条), 需要额外的设置一下属性为YES
59 if (isIOS(9.0)) {
60 // _locM.allowsBackgroundLocationUpdates = YES;
61 }
62
63
64 }
65
66
67 }
68 return _locM;
69 }
70
71
72
73
74 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
75 {
76
77 // 2. 开始更新用户位置
78 // start 开始某个服务 stop 停止某个服务
79 // 一旦我们调用了这个方法, 那么就会在后台不断的获取用户位置, 然后告诉外界
80 // 标准化定位(gps/ 基站 / WiFi)
81 //
82 [self.locM startUpdatingLocation];
83
84
85 // 显著位置变化(基站)(要求设备必须由电话模块)
86 // 当app 被杀死时也可以接收到位置通知(app -- 后台 )
87 // [self.locM startMonitoringSignificantLocationChanges];
88
89
90 /**
91 * ———————————应用场景—————————————
92 1) 如果要求定位及时,精度较高,并且运行时间较短,可使用标准定位;
93 2) 如果长时间监控用户位置,用户移动速度比较快(例如打车软件),可使用后者
94 *
95 */
96
97 /**
98 * extern const CLLocationAccuracy kCLLocationAccuracyBest;
99 extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
100 extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
101 extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
102 extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;ß
103 */
104
105 // [self.locM requestLocation];
106
107
108
109 }
110
111
112 #pragma mark - CLLocationManagerDelegate
113
114 /**
115 * 获取到位置信息时调用
116 *
117 * @param manager 位置管理者
118 * @param locations 位置数组
119 */
120 -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
121 {
122 // NSLog(@"获取到位置");
123
124 CLLocation *loc = [locations lastObject];
125
126
127 NSLog(@"%lf",loc.horizontalAccuracy);
128 // 代表当前位置 horizontalAccuracy>0 才是有效的
129 if(loc.horizontalAccuracy > 0)
130 {
131
132 /**
133 * CLLocation
134 * coordinate : 经纬度
135 altitude :海拔
136 course : 航向
137 speed : 速度
138 distanceFromLocation : 计算两个点之间的直线物理距离
139 */
140
141 /**
142 * 场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
143 例如:”北偏东 30度 方向,移动了 8米 ”
144 */
145
146 // 确定航向
147 NSString *angleStr = nil;
148 switch ((int)loc.course / 90) {
149 case 0:
150 angleStr = @"北偏东";
151 break;
152 case 1:
153 angleStr = @"东偏南";
154 break;
155 case 2:
156 angleStr = @"南偏西";
157 break;
158 case 3:
159 angleStr = @"西偏北";
160 break;
161
162 default:
163 angleStr = @"掉沟里去了";
164 break;
165 }
166
167 // 确定偏离角度
168 int angle = 0;
169 angle = (int)loc.course % 90;
170 // 正方向
171 if (angle == 0) {
172 angleStr = [angleStr substringToIndex:1];
173 }
174
175
176 // 移动了多少
177 CLLocationDistance distance = 0;
178 if (_lastLoc) {
179 distance = [loc distanceFromLocation:_lastLoc];
180 }
181 _lastLoc = loc;
182
183 // 拼串
184 // 例如:”北偏东 30度 方向,移动了 8米 ”
185
186 NSString *str ;
187 if (angle == 0) {
188 str = [NSString stringWithFormat:@"正%@方向, 移动了%f米", angleStr, distance];
189 }else
190 {
191 str = [NSString stringWithFormat:@"%@%zd度方向, 移动了%f米", angleStr , angle, distance];
192 }
193
194
195
196 NSLog(@"%@", str);
197
198 }
199
200 // 如果我们想要定位一次
201
202 // 停止位置更新
203 // [manager stopUpdatingLocation];
204 }
205
206 /**
207 * 当前授权状态发生变化时调用
208 *
209 * @param manager 位置管理者
210 * @param status 状态
211 */
212 -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
213 {
214 switch (status) {
215 case kCLAuthorizationStatusNotDetermined:
216 {
217 NSLog(@"用户未选择");
218 break;
219 }
220 case kCLAuthorizationStatusRestricted:
221 {
222 NSLog(@"受限制");
223 break;
224 }
225 case kCLAuthorizationStatusDenied:
226 {
227
228 // 确定当前设备, 是否支持定位,或者定位服务是否开启
229 if([CLLocationManager locationServicesEnabled])
230 {
231 NSLog(@"拒绝");
232
233 // 我们可以调用代码, 打开设置界面
234 NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
235 if ([[UIApplication sharedApplication] canOpenURL:url]) {
236 [[UIApplication sharedApplication] openURL:url];
237 }
238
239
240 }else
241 {
242 NSLog(@"服务关闭");
243 }
244
245 break;
246 }
247 case kCLAuthorizationStatusAuthorizedAlways:
248 {
249 NSLog(@"前后台定位授权");
250 break;
251 }
252 case kCLAuthorizationStatusAuthorizedWhenInUse:
253 {
254 NSLog(@"前台定位授权");
255 break;
256 }
257
258
259 default:
260 break;
261 }
262 }
263
264 /**
265 * 定位失败
266 *
267 * @param manager 位置管理者
268 * @param error 错误
269 */
270 -(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error
271 {
272 NSLog(@"fail%@",error);
273
274 }
275
276 @end