iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航

iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航_第1张图片
iu

首先要记住:苹果地图和高德地图的坐标系一样,百度地图和高德地图的坐标系不一样。高德和苹果都是使用的GCJ02坐标系(火星坐标系)。百度坐标系BD09,在GCJ02坐标系基础上再次加密。相同的坐标在不同的坐标系上存在坐标位置偏移。

关于坐标系的更多基础知识可参考:

http://lbsyun.baidu.com/index.php?title=coordinate


做这些功能首先肯定是查官方文档,怎么查?以高德地图为例:

iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航_第2张图片

  • 搜索关键字:调用地图
  • 文档在这:http://lbs.amap.com/api/amap-mobile/guide/ios/ios-uri-information/

百度地图文档在这:
http://lbsyun.baidu.com/index.php?title=uri/api/ios


苹果官方文档:

https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html


记住两个单词,不要混淆了:

  • latitude:
  • longitude:经度

设置白名单

LSApplicationQueriesSchemes
    
        iosamap
        baidumap
    

参考代码

#pragma mark - 去地图展示路线
/** 去地图展示路线 */
- (void)gotoMap{
    // 后台返回的目的地坐标是百度地图的
    // 百度地图与高德地图、苹果地图采用的坐标系不一样,故高德和苹果只能用地名不能用后台返回的坐标
    CGFloat latitude  = _consigneeModel.latitude.floatValue;  // 纬度
    CGFloat longitude = _consigneeModel.longitude.floatValue; // 经度
    NSString *address = _consigneeModel.address; // 送达地址
    
    // 打开地图的优先级顺序:百度地图->高德地图->苹果地图
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"baidumap://"]]) {
        // 百度地图
        // 起点为“我的位置”,终点为后台返回的坐标
        NSString *urlString = [[NSString stringWithFormat:@"baidumap://map/direction?origin={{我的位置}}&destination=%f,%f&mode=riding&src=快健康快递", latitude, longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:urlString];
        [[UIApplication sharedApplication] openURL:url];
    }else if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"iosamap://"]]) {
        // 高德地图
        // 起点为“我的位置”,终点为后台返回的address
        NSString *urlString = [[NSString stringWithFormat:@"iosamap://path?sourceApplication=applicationName&sid=BGVIS1&sname=%@&did=BGVIS2&dname=%@&dev=0&t=0",@"我的位置",address] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
    }else if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"http://maps.apple.com"]]){
        // 苹果地图
        // 起点为“我的位置”,终点为后台返回的address
        NSString *urlString = [[NSString stringWithFormat:@"http://maps.apple.com/?daddr=%@",address] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
    }else{
        // 快递员没有安装上面三种地图APP,弹窗提示安装地图APP
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"请安装地图APP" message:@"建议安装百度地图APP" preferredStyle:UIAlertControllerStyleAlert];
        [self presentViewController:alertVC animated:NO completion:nil];
    }
}

2019年6月12日更新

最近项目因为需要跳转到地图APP导航,所以我将这个功能模块封装了一下。

iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航_第3张图片
iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航_第4张图片

产品需求:

  1. 根据坐标导航
  2. 根据地址导航
  3. 根据“坐标+地址”导航

支持苹果地图、高德地图和百度地图。

注:我们后台返回的是高德坐标。

API如下:

@interface CQRouteManager : NSObject

/** 默认目的地名称,若未设置,默认为”目的地“ */
@property (class, nonatomic, copy) NSString *defaultDestinationName;

#pragma mark - 跳转到地图APP导航(“坐标” or “目的地名称” or “坐标+目的地名称”)

/**
 根据坐标导航
 
 @param controller 列表展示在此controller上
 @param coordinate 目的地坐标
 */
+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withCoordinate:(CLLocationCoordinate2D)coordinate;

/**
 根据目的地名称导航
 
 @param controller 列表展示在此controller上
 @param destination 目的地名称
 */
+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withDestination:(NSString *)destination;

/**
 根据”坐标+目的地名称“导航(尽量使用这个方法)
 
 @param controller 列表展示在此controller上
 @param coordinate 坐标
 @param destination 目的地名称
 */
+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withCoordate:(CLLocationCoordinate2D)coordinate destination:(NSString *)destination;


@end

实现:

#define SOURCE_APPLICATION [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]

/**
 路径导航类型
 
 - FVRouteNaviTypeApple: 苹果地图导航
 - FVRouteNaviTypeGaode: 高德地图导航
 - FVRouteNaviTypeBaidu: 百度地图导航
 */
typedef NS_ENUM(NSUInteger, FVRouteNaviType) {
    FVRouteNaviTypeApple,
    FVRouteNaviTypeGaode,
    FVRouteNaviTypeBaidu,
};

static NSString *_defaultDestinationName = @"目的地";

@implementation CQRouteManager

#pragma mark - 设置默认展示的目的地名称

+ (NSString *)defaultDestinationName {
    return _defaultDestinationName;
}

+ (void)setDefaultDestinationName:(NSString *)defaultDestinationName {
    _defaultDestinationName = defaultDestinationName;
}

#pragma mark - 跳转到地图APP导航(“坐标” or “目的地名称” or “坐标+目的地名称”)

/**
 根据坐标导航
 
 @param controller 列表展示在此controller上
 @param coordinate 目的地坐标
 */
+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withCoordinate:(CLLocationCoordinate2D)coordinate {
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    [self p_presentRouteNaviMenuOnController:controller withLocation:location destination:nil];
}

+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withDestination:(NSString *)destination {
    [self p_presentRouteNaviMenuOnController:controller withLocation:nil destination:destination];
}

+ (void)presentRouteNaviMenuOnController:(UIViewController *)controller withCoordate:(CLLocationCoordinate2D)coordinate destination:(NSString *)destination {
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    [self p_presentRouteNaviMenuOnController:controller withLocation:location destination:destination];
}

#pragma mark - private method

+ (void)p_presentRouteNaviMenuOnController:(UIViewController *)controller withLocation:(nullable CLLocation *)location destination:(nullable NSString *)destination {
    
    if (!location && !destination) {
        NSAssert(nil, @"位置和地址不能同时为空");
        return;
    }
    
    // 能否打开苹果地图
    BOOL canOpenAppleMap = NO;
    // 能否打开高德地图
    BOOL canOpenGaodeMap = NO;
    // 能否打开百度地图
    BOOL canOpenBaiduMap = NO;
    
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"http://maps.apple.com"]]) {
        canOpenAppleMap = YES;
    }
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"iosamap://"]]) {
        canOpenGaodeMap = YES;
    }
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"baidumap://"]]) {
        canOpenBaiduMap = YES;
    }
    
    // 三种地图都木有,弹窗提示,return
    if (!canOpenAppleMap && !canOpenGaodeMap && !canOpenBaiduMap) {
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"你手机未安装支持的地图APP" message:@"请先下载苹果地图、高德地图或百度地图" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:confirmAction];
        [controller presentViewController:alertVC animated:YES completion:nil];
        return;
    }
    
    
    //========== 以下是正常情况下的逻辑 ==========//
    
    // 地图列表
    UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"导航" message:@"请选择地图" preferredStyle:UIAlertControllerStyleActionSheet];
    
    //========== 使用苹果地图导航 ==========//
    if (canOpenAppleMap) {
        [alertVC addAction:[self p_actionWithNaviType:FVRouteNaviTypeApple title:@"使用苹果自带地图导航" location:location destination:destination]];
    }
    
    //========== 使用高德地图导航 ==========//
    if (canOpenGaodeMap) {
        [alertVC addAction:[self p_actionWithNaviType:FVRouteNaviTypeGaode title:@"使用高德地图导航" location:location destination:destination]];
    }
    
    //========== 使用百度地图导航 ==========//
    if (canOpenBaiduMap) {
        [alertVC addAction:[self p_actionWithNaviType:FVRouteNaviTypeBaidu title:@"使用百度地图导航" location:location destination:destination]];
    }
    
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertVC addAction:cancelAction];
    
    [controller presentViewController:alertVC animated:YES completion:nil];
}

+ (UIAlertAction *)p_actionWithNaviType:(FVRouteNaviType)naviType title:(NSString *)title location:(CLLocation *)location destination:(NSString *)destination {
    // 目的地如果为空,展示名称默认为”目的地“
    NSString *destinationName = destination ?: self.defaultDestinationName;
    
    __block NSString *urlString = nil;
    
    UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        switch (naviType) {
            case FVRouteNaviTypeApple: // 苹果地图
            {
                if (location) {
                    CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
                    MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
                    MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:loc addressDictionary:nil]];
                    toLocation.name = destinationName;
                    [MKMapItem openMapsWithItems:@[currentLocation, toLocation]
                                   launchOptions:@{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
                                                   MKLaunchOptionsShowsTrafficKey: [NSNumber numberWithBool:YES]}];
                } else {
                    // 没坐标,仅有目的地名称
                    urlString = [NSString stringWithFormat:@"http://maps.apple.com/?daddr=%@",destinationName];
                }
            }
                break;
                
            case FVRouteNaviTypeGaode: // 高德地图
            {
                if (location) {
                    // 有坐标时以坐标为准
                    urlString = [NSString stringWithFormat:@"iosamap://path?sourceApplication=%@&sid=BGVIS1&did=BGVIS2&dlat=%f&dlon=%f&dev=0&t=0&dname=%@",SOURCE_APPLICATION,location.coordinate.latitude, location.coordinate.longitude, destinationName];
                } else {
                    // 没有坐标时,以终点名称为准
                    urlString = [NSString stringWithFormat:@"iosamap://path?sourceApplication=%@&sname=%@&dname=%@&dev=0&t=0&sid=BGVIS1&did=BGVIS2",SOURCE_APPLICATION,@"我的位置",destinationName];
                }
            }
                break;
                
            case FVRouteNaviTypeBaidu: // 百度地图
            {
                if (location) {
                    // 注:高德用的gcj02坐标系
                    urlString = [NSString stringWithFormat:@"baidumap://map/direction?location=%f,%f&coord_type=gcj02&type=TIME&src=%@&origin={{我的位置}}&destination=%@", location.coordinate.latitude, location.coordinate.longitude, SOURCE_APPLICATION, destinationName];
                } else {
                    urlString = [NSString stringWithFormat:@"baidumap://map/direction?origin={{我的位置}}&destination=%@", destinationName];
                }
            }
                break;
        }
        
        // 打开地图APP
        if (urlString) {
            NSURL *targetURL = [NSURL URLWithString:[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
            if (@available(iOS 10.0, *)) {
                [[UIApplication sharedApplication] openURL:targetURL options:@{} completionHandler:^(BOOL success) {
                    NSLog(@"scheme调用结束");
                }];
            } else {
                // Fallback on earlier versions
                [[UIApplication sharedApplication] openURL:targetURL];
            }
        }
    }];
    
    return action;
}

demo

https://github.com/CaiWanFeng/iOS_Storage

demo所在位置(搜CQRouteManager)

你可能感兴趣的:(iOS开发笔记 | 跳转到百度、高德or苹果地图进行导航)