URI跳转方式地图导航的代码实践

本文转载至 http://adad184.com/2015/08/11/practice-in-mapview-navigation-with-URI/

前言

之前介绍了我正在做的是一款定位主打的应用 然后最近我们需要做一个定位导航的功能 能够让用户从当前位置导航到指定目的地(默认以驾车的方式导航)

手机上的导航方式 分应用内导航应用外导航

  • 应用内导航
    是指使用地图服务提供的SDK(比如高德,百度等等) 直接将导航功能嵌入到我们自己的APP内部
    但是这个方案我个人不喜欢 一是接入要一定的时间 二是增加APP的内存占用
  • 应用外导航
    是以URI跳转的方式(在iOS中就是以URL Scheme的方式) 直接跳到对应的地图APP中 直接利用对方的功能来导航
    这样的优点 一是接入方便 二是不增加自己APP的开销 缺点就是如果用户没有装这个地图应用就没办法使用这个地图的服务

说起应用内导航 当年是被图吧坑惨了 两年前 高德和百度都没有推出导航SDK的时候 市面上好像就只有图吧有应用内导航SDK 所以不得已用了图吧SDK 如今图吧SDK仍是我心中最难用的地图SDK(话说百度的SDK和图吧的SDK设计感觉上是一脉相承的 不晓得是不是百度做地图时挖了一大批图吧的人?) 而且就是这个难用的SDK 竟然还是收费的

而今天要说的 就是第二种 因为网上说的都不是很全面 所以今天把对这种方式的研究结果总结一下

研究

先来看一下我们要达到什么效果 就是当我们点导航的时候 会弹出下面这个选择列表

URI跳转方式地图导航的代码实践

当然 如果没有安装某个地图APP 那么对应的选项是不会出现的 检测APP是否安装 只要调用下面这个方法就可以了

1
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"appurlscheme://"]

关于APP的URL Scheme相关内容这里就不介绍了 大家可以自行去研究

那么我们上图提到了4个地图应用 分别是

  1. 苹果地图
  2. 百度地图
  3. 高德地图
  4. 谷歌地图

这些也是当前我们用得最多的几种地图了(什么 你们说还有腾讯地图? 可惜腾讯地图暂时还不支持URI的方式打开 所以这里就没列出来 等可以用了我会补上)

下面来对比一下几种地图

地图 URL Scheme 文档 是否可以跳回到APP
苹果地图   文档
百度地图 baidumap:// 文档
高德地图 iosamap:// 文档
谷歌地图 comgooglemaps:// 文档

苹果地图是系统自带的(而且苹果地图最好的方式也不是用URI的方式开打) 所以无需URL Scheme就可以打开的
其次 当跳到地图APP之后可以跳回是一种很好的体验(参考微信的跳转) 但是遗憾的是 苹果地图和百度地图都不支持跳回

接下来我们就回到正题 说一说每种地图的跳转方式

假设我们有一个指定的目的坐标coordinate 而我们自己的APP的URL Scheme是urlScheme 名称是appName

1
2
3
CLLocationCoordinate2D coordinate;
NSString *urlScheme;
NSString *appName;

苹果地图


苹果地图可以通过openURL的方式打开

1
2
3
NSString *urlString = [[NSString stringWithFormat:@"http://maps.apple.com/?daddr=%f,%f&saddr=slat,slng",coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

但是这种方式 不能以当前位置为起点 所以不符合我们的要求 网上说可以用下面这种方式 但是我没成功

1
NSString *urlString = [[NSString stringWithFormat:@"http://maps.apple.com/?daddr=%f,%f&saddr=Current+Location",coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

但是苹果提供了另一种方式 使用MKMapItem

1
2
3
4
5
6
MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:nil]]; [MKMapItem openMapsWithItems:@[currentLocation, toLocation]
launchOptions:@{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey: [NSNumber numberWithBool:YES]}];

效果如下
URI跳转方式地图导航的代码实践

百度地图


1
2
3
NSString *urlString = [[NSString stringWithFormat:@"baidumap://map/direction?origin={{我的位置}}&destination=latlng:%f,%f|name=目的地&mode=driving&coord_type=gcj02",coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

要注意几点

  1. origin=
    这个是不能被修改的 不然无法把出发位置设置为当前位置
  2. destination=latlng:%f,%f|name=目的地
    name=XXXX name这个字段不能省略 否则导航会失败 而后面的文字则可以随便填
  3. coord_type=gcj02
    coord_type允许的值为bd09ll、gcj02、wgs84 如果你APP的地图SDK用的是百度地图SDK 请填bd09ll 否则 就填gcj02 wgs84你基本是用不上了(关于地图加密这里也不多谈 请自行学习)

效果如下
URI跳转方式地图导航的代码实践

高德地图


1
2
3
NSString *urlString = [[NSString stringWithFormat:@"iosamap://navi?sourceApplication=%@&backScheme=%@&lat=%f&lon=%f&dev=0&style=2",appName,urlScheme,coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

要注意几点

  1. sourceApplication=%@&backScheme=%@
    sourceApplication代表你自己APP的名称 会在之后跳回的时候显示出来 所以必须填写 backScheme是你APP的URL Scheme 不填是跳不回来的哟
  2. dev=0
    这里填0就行了 跟上面的gcj02一个意思 1代表wgs84 也用不上

效果如下
URI跳转方式地图导航的代码实践

退出导航后 会提示是否跳回到APP
URI跳转方式地图导航的代码实践

谷歌地图


1
2
3
NSString *urlString = [[NSString stringWithFormat:@"comgooglemaps://?x-source=%@&x-success=%@&saddr=&daddr=%f,%f&directionsmode=driving",appName,urlScheme,coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

要注意几点

  1. x-source=%@&x-success=%@
    跟高德一样 这里分别代表APP的名称和URL Scheme
  2. saddr=
    这里留空则表示从当前位置触发

效果如下 在有多条路线的时候 谷歌地图会让你选择其中一条
URI跳转方式地图导航的代码实践

选择之后就进入了导航页面
URI跳转方式地图导航的代码实践

腾讯地图

既然提到了腾讯地图 那么还是说一下 从网上和官方文档可以得知 大概调用的URI如下

1
2
3
NSString *urlString = [[NSString stringWithFormat:@"qqmap://map/routeplan?type=drive&fromcoord=CurrentLocation&tocoord=%f,%f&coord_type=1&policy=0",coordinate.latitude, coordinate.longitude] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

但是很遗憾 调用之后出错了 无法导航

效果如下
URI跳转方式地图导航的代码实践

补充说明

iOS9发布以后 很多朋友发现openURL的方式都失败了 这是因为iOS对openURL做了进一步限制
不过适配起来也很简单 在plist中加一条名为LSApplicationQueriesSchemes的Array类型的Key 并把上述地图的scheme添加进去就行了 如图
URI跳转方式地图导航的代码实践

小结


文中的demo可以在这里找到

相对来说 高德地图做得更用心一点 毕竟也是苹果的服务提供商 而百度相对来说则差一点 谷歌的话 不*还是用不了 而苹果自带的地图则不多说了 功能还是太简单了

这里只是用最简单的方式对导航功能进行了调用 各家的地图其实还有很多参数和功能没有使用到 需要知道的同学可以在文章开头的文档链接中找到详细的描述

上一篇:lintcode 中等题:Singleton number II 落单的数 II


下一篇:网络-console