地图与定位

地图与定位的使用场景

  • 导航
  • 社交
  • O2O
  • 手游
  • 室内定位

定位

用于定位的方式:GPS/wifi/蜂窝基站/iBeacon
  • 可用于计算方向

  • CoreLocation.framework用于进行定位计算

  • 定位权限

  • 耗电

定位服务

Standard location service:标准定位服务(GPS/wifi/蜂窝基站/iBeacon)

Significant-change location service 通过基站进行定位服务

Region monitoring  用作区域检测

定位权限申请

地图与定位_第1张图片
用途说明

主要应用的类:CLLocationManager

//判断定位服务是否被使用
+ (BOOL)locationServicesEnabled API_AVAILABLE(ios(4.0), macos(10.7));
//用户对这个app所使用的授权状态
+ (CLAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(4.2), macos(10.7));
//申请定位服务,用户首次调用的时候会触发一个弹窗,让用户来选择是否允许
- (void)requestWhenInUseAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos);
- (void)requestAlwaysAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos) API_UNAVAILABLE(tvos);
//启动位置更新/停止位置更新
- (void)startUpdatingLocation API_AVAILABLE(watchos(3.0)) API_UNAVAILABLE(tvos);
- (void)stopUpdatingLocation;

CLLocationManager的一些属性

//位置变化更新的一个最小距离,当用户的移动大于这个距离才会更新
@property(assign, nonatomic) CLLocationDistance distanceFilter;
//定位精度
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
//表示用户当前的位置
@property(readonly, nonatomic, copy, nullable) CLLocation *location;

CLAuthorizationStatus这个授权状态的枚举

       //用户还没有进行配置
    kCLAuthorizationStatusNotDetermined = 0,
        //受限制
    kCLAuthorizationStatusRestricted,
        //拒绝
    kCLAuthorizationStatusDenied,
        //始终允许定位
    kCLAuthorizationStatusAuthorizedAlways API_AVAILABLE(macos(10.12), ios(8.0)),
        //在前台的时候允许使用定位
    kCLAuthorizationStatusAuthorizedWhenInUse API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos)

定位权限获取

  • 隐式获取权限
[locationManager startUpdatingLocation];
  • 显示获取权限
if([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
{
     [locationManager requestWhenInUseAuthorization];
}

判断是否已经决定了定位权限

  if (![CLLocationManager locationServicesEnabled])
    {
        NSLog(@"Location Service is Off!");
        return;
    }

获得的定位权限是什么

+(BOOL)authorized
{
 return [CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse||CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways||[CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorized;
}

+(BOOL)denined
{
 return [CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied;
}

open system setting(引导用户打开定位设置项)

- (void)gotoSetting:(id)sender
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}

CLLocationManagerDelegate

//返回定位权限或者位置变化
//状态发生变化
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_AVAILABLE(ios(4.2), macos(10.7));
//发生错误时
- (void)locationManager:(CLLocationManager *)manager
    didFailWithError:(NSError *)error;
//位置发生变化
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations API_AVAILABLE(ios(6.0), macos(10.9));

CLLocation表示某个位置的定位信息

地图与定位_第2张图片
CLLocation,如果horizontalAccuracy只传负值得话表示当前的这个点是无效的。

CLPlacemark地标

地图与定位_第3张图片
image.png

定位-CLGeocoder 需要注意的点

  • 地理编码(geocoder)
    根据给定的位置(通常是地名)确定地理坐标(经、纬度)。
  • 反地理编码(Reverse geocoder)
    根据地理坐标(经、纬度)获得位置信息(城市,道路等)

模拟器定位调试

地图与定位_第4张图片
image.png

demo

1.添加CoreLocation.framework
2.添加info.plist 权限描述
3.在需要的类中添加#import

#import 

@interface ViewController ()
{
    CLLocationManager *_locationManager;
    
    CLGeocoder *_geoCoder;
}

- (void)viewDidLoad{
 //定位权限
    _locationManager =[[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    
    
    if (![CLLocationManager locationServicesEnabled])
    {
        NSLog(@"Location Service is Off!");
        return;
    }
    
    //请求定位服务
    [_locationManager requestWhenInUseAuthorization];
      [self startMonitorLocation];

}

- (void)startMonitorLocation
{ 
   //精确定位
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//位置变化更新的一个最小距离,当用户的移动大于这个距离才会更新
    _locationManager.distanceFilter = 50;
    //开始定位
    [_locationManager startUpdatingLocation];
}

- (void)stopMonitorLocation
{
    [_locationManager stopUpdatingLocation];
}


判断用户是否拒绝了定位权限

#pragma mark - location delegate
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    //当判断用户拒绝这个定位权限时候,引导用户打开这个定位设置界面
    if(status==kCLAuthorizationStatusDenied)
    {
        //这里是点击这个按钮跳转,可以通过别的形式引导用户跳转别的位置
        UIButton *button = [[UIButton alloc] init];
        [button setTitle:@"goto setting" forState:UIControlStateNormal];
        [button setBackgroundColor:[UIColor orangeColor]];
        [button setFrame:CGRectMake(100, 100, 150, 50)];
        [button addTarget:self action:@selector(gotoSetting:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    }
  

    NSLog(@"CLAuthorizationStatus %zd", status);
}

#pragma mark - button
- (void)gotoSetting:(id)sender
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}

获取定位数据

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations firstObject];
//当前打印出来的是经纬度信息
    NSLog(@"location updated! %@", [NSString stringWithFormat:@"latitude %f, longtitude %f", location.coordinate.latitude, location.coordinate.longitude]);
    //用反地理编码将经纬度转成真实的地理信息
    if (!_geoCoder) {
        _geoCoder = [[CLGeocoder alloc] init];
    }
    [_geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
       //从placemark中可以取出地理城市,国家等信息
        for (CLPlacemark *placemark in placemarks)
        {
            NSLog(@"name=%@,locality=%@ country=%@", placemark.name, placemark.locality, placemark.country);
        }
        
    }];
}

定位出错的时候加入出错处理

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"location error");
    switch ([error code]) {
        case kCLErrorDenied:
            [self stopMonitorLocation];
            break;
        case kCLErrorLocationUnknown:
            [self stopMonitorLocation];
            break;
        default:
            break;
    }
}
地图类型
typedef NS_ENUM(NSUInteger,MKMapType)
{
//标准地图
MKMapTypeStandard
//卫星地图
MKMapTypeStatellite
//标准和卫星混合模式
MKMapTypeHybrid
//3D立体地图
MKMapTypeStatelliteFlyover,
MKMapTypeHybridFlyover
}
地图与定位_第5张图片
位置跟踪
typedef NS_ENUM(NSInteger, MKUserTrackingMode) {
    MKUserTrackingModeNone = 0, // the user's location is not followed
       //跟踪用户当前位置
    MKUserTrackingModeFollow, // the map follows the user's location
        //跟踪用户的朝向
    MKUserTrackingModeFollowWithHeading __TVOS_PROHIBITED, // the map follows the user's location and heading
} NS_ENUM_AVAILABLE(NA, 5_0) __TVOS_AVAILABLE(9_2) __WATCHOS_PROHIBITED;

MKMapView

地图与定位_第6张图片
设置地图控制选项

MKMapViewDelegate

地图与定位_第7张图片
MKMapViewDelegate
//返回用户当前的位置
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation NS_AVAILABLE(10_9, 4_0);
//错位就返回fail
- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error NS_AVAILABLE(10_9, 4_0);

Demo:展示用户当前的位置

1.设置mapview

    //step1
    _mapView = [[MKMapView alloc] init];
    _mapView.frame = self.view.frame;
    _mapView.delegate = self;
    //设置为标准地图
    _mapView.mapType = MKMapTypeStandard;
    //地图上显示的信息
    _mapView.showsUserLocation = YES;
    _mapView.showsScale = YES;
    _mapView.showsTraffic = YES;
    _mapView.showsCompass = YES;
    //跟踪位置并且记录前进方向
    _mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
    self.view = _mapView;

  //申请定位权限
    _locationManager = [[CLLocationManager alloc] init];
    [_locationManager requestWhenInUseAuthorization];
    //反编码获取坐标对应地点
    _geocoder = [[CLGeocoder alloc] init];
    //点数据
    _pointAnnotation = [[MKPointAnnotation alloc] init];
    _pointAnnotation.title = @"奶茶 刘若英";
    _pointAnnotation.subtitle = @"原来你也在这里 盛大开演";
    CLLocationCoordinate2D coordinate;
    coordinate.latitude = 30.189845;
    coordinate.longitude = 120.187883;
    _pointAnnotation.coordinate = coordinate;
    [_mapView addAnnotation:_pointAnnotation];
    
    self.availableMaps = [NSMutableArray array];
    [self getAvailableMapsApps];

#pragma mark - mapview delegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    [_geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
       
        if (placemarks.count > 0)
        {
            CLPlacemark *placemark = placemarks[0];
            userLocation.title = @"当前位置";
            userLocation.subtitle = [NSString stringWithFormat:@"%@ %@", placemark.locality, placemark.thoroughfare];
        }
        
    }];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
    if ([annotation isKindOfClass:[MKPointAnnotation class]])
    {
        NSString *pointAnnotationIdentifier = @"pointAnnotationIdentifier";
        MKAnnotationView *annotationView = [_mapView dequeueReusableAnnotationViewWithIdentifier:pointAnnotationIdentifier];
        if (!annotationView) {
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointAnnotationIdentifier];
            
            UIButton *testButton = [[UIButton alloc] init];
            [testButton setBackgroundColor:[UIColor orangeColor]];
            [testButton setTitle:@"Go" forState:UIControlStateNormal];
            testButton.frame = CGRectMake(0, 0, 50, 50);
            [testButton addTarget:self action:@selector(go:) forControlEvents:UIControlEventTouchUpInside];
            annotationView.rightCalloutAccessoryView = testButton;
        }
        annotationView.annotation = _pointAnnotation;
        annotationView.canShowCallout = YES;
        return annotationView;
    }
    return nil;
}

跳转到第三方导航登录

#pragma mark - button
- (void)go:(id)sender
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"选择导航" message:@"选择你要的导航服务" preferredStyle:UIAlertControllerStyleActionSheet];
    
    UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"系统导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
       
        CLLocationCoordinate2D coordinateEnd = CLLocationCoordinate2DMake(31.18, 121.43);
        MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinateEnd];
        MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:placemark];
        toLocation.name = @"目的地";
        
        MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
        
        [MKMapItem openMapsWithItems:@[currentLocation, toLocation] launchOptions:@{
                                                                                    MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
                                                                                    MKLaunchOptionsShowsTrafficKey:@YES
                                                                                    }];
    }];
    
    [alert addAction:action1];
    
    for (NSDictionary *dic in self.availableMaps)
    {
        UIAlertAction *action2 = [UIAlertAction actionWithTitle:[NSString stringWithFormat:@"使用%@导航", dic[@"name"]] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
           
            NSString *string = dic[@"url"];
            string = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
            NSURL *url = [NSURL URLWithString:string];
            [[UIApplication sharedApplication] openURL:url];
        }];
        [alert addAction:action2];
    }
    
    UIAlertAction *action3 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alert addAction:action3];
    
    [self presentViewController:alert animated:YES completion:nil];
    
}

- (void)getAvailableMapsApps
{
    [self.availableMaps removeAllObjects];
    
    CLLocationCoordinate2D coordinateStart = CLLocationCoordinate2DMake(30.19, 120.19);
    CLLocationCoordinate2D coordinateEnd = CLLocationCoordinate2DMake(30.23, 120.15);
    
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"baidumap://"]])
    {
        NSString * urlString = [NSString stringWithFormat:@"baidumap://map/direction?origin=latlng:%f,%f|name:我的位置&destination=latlng:%f,%f|name:目的地&mode=driving",coordinateStart.latitude,coordinateStart.longitude,coordinateEnd.latitude,coordinateEnd.longitude];
        
        NSDictionary *dic = @{@"name" : @"百度地图", @"url" : urlString};
        [self.availableMaps addObject:dic];
    }
}


你可能感兴趣的:(地图与定位)