展示MKMapView唤起内置导航功能
需求如下:
点击该页面地址或者点击定位地点唤醒地图类APP
屏幕快照 2018-09-05 下午6.10.14.png地图上面显示的定位地点是从服务端获取的经纬度 比如CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(39.92, 116.3);
思路:
定义一个view,里面含有mapView相关功能,传入当前需要展示在地图上面的经纬度位置信息。
代码块
需要的框架
CoreLocation.framework
MapKit.framework
.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface ZHMapManagerView : UIView
@property(nonatomic,strong)NSArray *annotationPins;
//设置目的地的经纬度 展示在地图上面
- (void)setLatitudeAndLongitude:(CLLocationDegrees)latitude
longitude:(CLLocationDegrees)longitude;
@end
.m 首先需要导入#import <MapKit/MapKit.h>
@interface ZHMapManagerView ()<MKMapViewDelegate,CLLocationManagerDelegate>
//创建一个位置管理器
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) MKMapView *mapView;
创建mapView
@implementation ZHMapManagerView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self createMapView];
}
return self;
}
- (void)createMapView
{
self.mapView = [[MKMapView alloc] initWithFrame:self.bounds];
_mapView.delegate = self;
//跟踪位置 设置map的跟踪模式
_mapView.userTrackingMode = MKUserTrackingModeFollow;
//不显示用户的当前位置
_mapView.showsUserLocation = NO;
// 地图类型效果
_mapView.mapType = MKMapTypeStandard;
[self addSubview:_mapView];
self.locationManager = [[CLLocationManager alloc] init];
WS(weakSelf)
//请求用户授权
[self openLocationServiceWithBlock:^(BOOL locationIsOpen) {
if (!locationIsOpen) {
[weakSelf.locationManager requestWhenInUseAuthorization];
}
}];
}
- (void)openLocationServiceWithBlock:(void(^)(BOOL locationIsOpen))returnBlock
{
if ([CLLocationManager locationServicesEnabled])
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
switch (status) {
case kCLAuthorizationStatusNotDetermined:
NSLog(@"定位服务授权状态是:用户没有决定是否使用定位服务");
returnBlock(NO);
break;
case kCLAuthorizationStatusRestricted:
returnBlock(NO);
NSLog(@"定位服务授权状态是受限制的");
break;
case kCLAuthorizationStatusDenied:
NSLog(@"定位服务授权状态已经被用户明确禁止,或者在设置里的定位服务中关闭");
break;
case kCLAuthorizationStatusAuthorizedAlways:
returnBlock(YES);
NSLog(@"定位服务授权状态已经被用户允许在任何状态下获取位置信息");
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
NSLog(@"定位服务授权状态仅被允许在使用应用程序的时候");
returnBlock(YES);
break;
default:
break;
}
}else
{
NSLog(@"定位服务不可用");
}
}
注意事项
需要在info.plist文件中增加这个 请求用户授权
屏幕快照 2018-09-05 下午6.52.21.png
iOS10 对隐私权限的管理
比如访问的摄像头、麦克风等硬件,都需要提前请求应用权限、允许后才可以使用,或者现在要提前声明,虽然以往要求不严格。比如在iOS10中访问通讯录时,强制必须在Info.plist中加入NSContactsUsageDescription等描述,否则应用会崩溃。
定位权限:Privacy - Location When In Use Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据
定位权限: Privacy - Location Always Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据
pragma mark - MKMapViewDelegate
//自定义显示在地图上面大头针的图片样式 我只是改了图片
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[ZHMyAnnotation class]]) {
static NSString *identifier = @"myAnnotation";
MKAnnotationView *annotationView =[_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.canShowCallout = NO;//能否显示大头针详情
}
annotationView.annotation = annotation;
annotationView.image = ((ZHMyAnnotation *)annotation).image;
return annotationView;
} else {
return nil;
}
}
//点击大头针
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
[self navigateTolatitude:30 longitude:116];
}
pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if (error) {
NSLog(@"获取用户当前位置失败");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation *newLocation = locations[0];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *array, NSError *error){
if (array.count > 0){
CLPlacemark *placemark = [array objectAtIndex:0];
CLLocationDegrees latitude=placemark.location.coordinate.latitude;
CLLocationDegrees longitude=placemark.location.coordinate.longitude;
NSString *city = [NSString stringWithFormat:@"%@%@",placemark.administrativeArea ? placemark.administrativeArea : @"",placemark.locality ? placemark.locality : @""];
NSLog(@"adress---%@",[NSString stringWithFormat:@"%@ %@ %@ %@",placemark.country,city,placemark.name,placemark.thoroughfare]);
NSLog(@"%@",[NSString stringWithFormat:@"经度:%.3f,纬度:%.3f",longitude,latitude]);
}
else if (error == nil && [array count] == 0)
{
NSLog(@"地图加载失败");
}
else if (error != nil)
{
NSLog(@"地图加载失败");
}
}];
[manager stopUpdatingLocation];
}
地理编码和反地理编码都使用CLGeocoder类来实现.
反地理编码
使用reverseGeocodeLocation: completionHandler: 方法.将一个包含经纬度的CLLocation传进去,得到位置信息,就是反地理编码。
在得到的CLPlacemark中取出name信息即可。如上代码⬆️
地理编码
使用 geocodeAddressString: completionHandler: 方法.将一个地名字符串转换为经纬度。
在此方法中得到一个装着CLPlacemark的数组。一个CLPlacemark表示一个地理坐标,有位置信息(经纬度),以及地理位置的详情。将CLPlacemark中的经纬度取出,就完成了地理编码
实现导航功能
本次需求是唤起苹果内置的导航即可。地图导航所需的数据拿不到,交由苹果处理,在中国苹果交友高德地图处理。由于封装的比较好,我们本质上只需要一行代码:
MKMapItem openMapsWithItems: launchOptions:
代码块:
- (void)navigateTolatitude:(CLLocationDegrees)latitude
longitude:(CLLocationDegrees)longitude
{
MKMapItem *currentLocation =[MKMapItem mapItemForCurrentLocation];
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil]];
[MKMapItem openMapsWithItems:@[currentLocation,toLocation] launchOptions:@{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey:[NSNumber numberWithBool:YES]}];
}
1.首先获取地理编码目的地位置
使用CLGeocoder进行地理编码,得到CLPlacemark, 转换CLPlacemark --> MKPlacemark
MKPlacemark *mkPlacemark = [[MKPlacemark alloc] initWithPlacemark:placemark];
2、获取当前位置和目的位置的mapItem
//当前位置
MKMapItem *currentLocation =[MKMapItem mapItemForCurrentLocation];
//目的地位置
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil]];
3、开始导航
第一个参数传入目的地和当前位置的数组,第二个是选项的字典。
[MKMapItem openMapsWithItems:@[currentLocation,toLocation] launchOptions:@{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey:[NSNumber numberWithBool:YES]}];
//keys
MKLaunchOptionsMapCenterKey:地图中心的坐标(NSValue)
MKLaunchOptionsMapSpanKey:地图显示的范围(NSValue)
MKLaunchOptionsShowsTrafficKey:是否显示交通信息(boolean NSNumber)
//MKLaunchOptionsDirectionsModeKey: 导航类型(NSString)
{
MKLaunchOptionsDirectionsModeDriving:驾车
MKLaunchOptionsDirectionsModeWalking:步行
}
//MKLaunchOptionsMapTypeKey:地图类型(NSNumber)
enum {
MKMapTypeStandard = 0,
MKMapTypeSatellite,
MKMapTypeHybrid
};//MKLaunchOptionsCameraKey 3D地图效果
以上是针对app内展示经纬度和导航去这里的基本代码。