首先要记住:苹果地图和高德地图的坐标系一样,百度地图和高德地图的坐标系不一样。高德和苹果都是使用的GCJ02坐标系(火星坐标系)。百度坐标系BD09,在GCJ02坐标系基础上再次加密。相同的坐标在不同的坐标系上存在坐标位置偏移。
关于坐标系的更多基础知识可参考:
http://lbsyun.baidu.com/index.php?title=coordinate
做这些功能首先肯定是查官方文档,怎么查?以高德地图为例:
- 搜索关键字:调用地图
- 文档在这: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导航,所以我将这个功能模块封装了一下。
产品需求:
- 根据坐标导航
- 根据地址导航
- 根据“坐标+地址”导航
支持苹果地图、高德地图和百度地图。
注:我们后台返回的是高德坐标。
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