可先建项目直接运行学习
info.plist文件设置:
模拟器模拟运动场景:
.m文件代码
//
// ViewController.m
// CoreLocation
//
// Created by admin on 17/2/21.
// Copyright © 2017年 zengchunjun. All rights reserved.
//
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#define IOS7_Later [[UIDevice currentDevice].systemVersion floatValue] >= 7.0
#define IOS8_Later [[UIDevice currentDevice].systemVersion floatValue] >= 8.0
#define IOS9_Later [[UIDevice currentDevice].systemVersion floatValue] >= 9.0
#define IOS10_Later [[UIDevice currentDevice].systemVersion floatValue] >= 10.0
@interface ViewController ()<CLLocationManagerDelegate>
@property (nonatomic,strong)CLLocationManager *locationManager;
@property (nonatomic,strong)CLLocation *lastLoc;
@end
@implementation ViewController
- (CLLocationManager *)locationManager
{
if (_locationManager == nil) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
// 如果是ios8.0以后, 在想请求用户的位置信息, 需要主动的请求授权
// 使用时授权
[_locationManager requestWhenInUseAuthorization];
// 前后台定位授权
// [_locationManager requestAlwaysAuthorization];
// 如果当前的授权状态是前后台定位授权, 那么默认情况下, 就可以在后台获取用户位置信息, 不需要勾选后台模式location updates
// 使用时授权 + 勾选后台模式location updates
// [_locationManager requestWhenInUseAuthorization];
// 效果 在后台确实可以获取到位置信息, 但是屏幕上方会出现一个蓝色的横幅, 不断提醒用户, 当前APP 正在使用你的位置
// 对于这个在后台使用定位的方式,在iOS 9之后需要加一句代码
// _locationManager.allowsBackgroundLocationUpdates = YES;
}
// 设置过滤距离
// 每隔100米定位一次
// 1 111KM/100M
// 如果最新的位置距离上一次的位置之间的物理距离, 大于这个值, 就会通过代理来告诉我们最新的位置数据
_locationManager.distanceFilter = 10;
// 定位精确度
// kCLLocationAccuracyBestForNavigation // 最适合导航
// kCLLocationAccuracyBest; // 最好的
// kCLLocationAccuracyNearestTenMeters; // 附近10米
// kCLLocationAccuracyHundredMeters; // 附近100米
// kCLLocationAccuracyKilometer; // 附近1000米
// kCLLocationAccuracyThreeKilometers; // 附近3000米
// 经验: 如果定位的精确度越高, 那么越耗电, 而且定位时间越长
//
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
return _locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 标准定位服务 (gps/wifi/蓝牙/基站)
[self.locationManager startUpdatingLocation];
// 不能与 startUpdatingLocation同时使用
// 必须实现代理的定位失败的方法 iOS 9以后的方法
// [self.locationManager requestLocation];
// 显著位置变化的服务(基站进行定位, 电话模块)
// [self.locationManager startMonitoringSignificantLocationChanges];
if ([CLLocationManager headingAvailable]) {// 判断 "磁力计"传感器 是否可用
[self.locationManager startUpdatingHeading];
}else
{
NSLog(@"当前磁力计设备不可用");
}
// CLLocation属性详解
// coordinate: 经纬度信息
// altitude: 海拔信息
// horizontalAccuracy: 如果整个数字是负数, 就代表位置数据无效
// verticalAccuracy: 如果整个数字是负数, 就代表海拔数据无效
// course: 航向
// speed: 速度
// distanceFromLocation: 计算两个经纬度坐标之间的物理指向距离
// 计算两点之间的距离
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:21.123 longitude:121.345];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:22.123 longitude:121.345];
CLLocationDistance distance = [loc1 distanceFromLocation:loc2];
NSLog(@"%.2f",distance);
}
#pragma mark CLLocationManagerDelegate
// 检查磁力计朝向
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// 1. 拿到当前设备朝向
/// 0- 359.9 角度
CLLocationDirection angle = newHeading.magneticHeading;
// 1.1 把角度转换成为弧度
CGFloat hudu = (angle / 180 * M_PI);
// 2. 反向旋转图片(弧度)
// UIView.animateWithDuration(0.5) {
// self.compassView.transform = CGAffineTransformMakeRotation(-hudu)
// }
[UIView animateWithDuration:0.5 animations:^{
}];
}
// 位置信息改变
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSLog(@"获取到位置信息");
CLLocation *newLocation = locations.lastObject;
// guard let newLocation = locations.last else {return}
if (newLocation.horizontalAccuracy < 0) return;
// CLLocation
// coordinate: 经纬度信息
// altitude: 海拔信息
// horizontalAccuracy: 如果整个数字是负数, 就代表位置数据无效
// verticalAccuracy: 如果整个数字是负数, 就代表海拔数据无效
// course: 航向
// speed: 速度
// distanceFromLocation: 计算两个经纬度坐标之间的物理指向距离
// 场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
// 例如:”北偏东 30度 方向,移动了 8米”
// 1. 获取当前的行走航向
NSArray *angleStrs = @[@"北偏东", @"东偏南", @"南偏西", @"西偏北"];
int index = (int)(newLocation.course) / 90;
NSString *angleStr = angleStrs[index];
// 2. 行走的偏离角度
int angle = (int)(newLocation.course) % 90;
if (angle == 0) {
angleStr = [@"正" stringByAppendingString:[angleStr substringToIndex:1]];
}
// 3. 移动了多少米
CLLocation *lastLocation = _lastLoc ? _lastLoc : newLocation;
CLLocationDistance distance = [newLocation distanceFromLocation:lastLocation];
_lastLoc = newLocation;
// 4. 合并字符串, 打印
// 例如:”北偏东 30度 方向,移动了 8米”
if (angle == 0) {
// print(angleStr + "方向, 移动了\(distance)米")
NSLog(@"%@",[NSString stringWithFormat:@"%@方向,移动了%.2f米",angleStr,distance]);
}else
{
// print(angleStr + "\(angle)" + "方向, 移动了\(distance)米")
NSLog(@"%@",[NSString stringWithFormat:@"%@%d方向,移动了%.2f米",angleStr,angle,distance]);
}
}
// 定位失败
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"定位失败");
}
// 授权状态改变
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
// kCLAuthorizationStatusNotDetermined = 0,
//
// kCLAuthorizationStatusRestricted,
//
// kCLAuthorizationStatusDenied,
//
// kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(10_12, 8_0),
//
// kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0),
//
// kCLAuthorizationStatusAuthorized
switch (status) {
case kCLAuthorizationStatusNotDetermined:
printf("用户没有决定");
break;
case kCLAuthorizationStatusRestricted:
printf("受限制");
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
printf("前台定位授权");
break;
case kCLAuthorizationStatusAuthorizedAlways:
printf("前后台定位授权");
break;
case kCLAuthorizationStatusDenied:
// print("拒绝")
// 判断当前设备是否支持定位, 并且定位服务是否开启
if ([CLLocationManager locationServicesEnabled]) {
printf("真正被拒绝");
// 手动通过代码, 来跳转到设置界面
if (IOS8_Later) {
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@""} completionHandler:nil];
}
}
}else {
// 当我们在app内部想要访问用户位置, 但是当前的定位服务是关闭状态, 那么系统会自动弹出一个窗口, 快捷跳转到设置界面, 让用户设置
printf("定位服务应该打开");
}
break;
default:
printf("none");
break;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end