效果图
前言
为什么调用第三方呢?集成在App里面不行吗?
- 接入导航SDK,以百度为例,apk包体积能增加小几十兆之多,上一版本还是几兆的apk,迭代一版本直接几十兆了,落差之大,难以接受。
- 虽说当下流量不值钱了,但是下载时长越久,客户丢失率越高。
- 最关键的是,当下地图并非一家独大,客户应该有自主选择的权利,你集成了百度,但用户却钟爱于高德,这极为尴尬。
- 且当下包括微信等一众主流App都是通过调用第三方地图来做的,这显然有一定道理,也是大势所趋。
- 坑多,显然是干不过别人一个团队专门来做地图的,不如站在巨人的肩上。
综上所诉,优点显而易见。
坐标系
有地图就有经纬度,有经纬度就扯到坐标系,简单介绍一下坐标系。
主要有以下三种:
- WGS84:一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。
- GCJ02:由中国国家测绘局制订的地理信息系统的坐标系统,是由WGS84坐标系经过加密后的坐标系。
- BD09:百度坐标系,在GCJ02坐标系基础上再次加密。其中BD09LL表示百度经纬度坐标,BD09MC表示百度墨卡托米制坐标。
更多的坐标知识介绍
百度使用的自家BD09LL坐标系,高德和腾讯都是GCJ02即火星坐标系,所以相互之间是需要转换的,不然会有位置偏移。
转换方法:
/** * BD-09 坐标转换成 GCJ-02 坐标 */ public static LatLng BD2GCJ(LatLng bd) { double x = bd.longitude - 0.0065, y = bd.latitude - 0.006; double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI); double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI); double lng = z * Math.cos(theta); double lat = z * Math.sin(theta); return new LatLng(lat, lng); } /** * GCJ-02 坐标转换成 BD-09 坐标 */ public static LatLng GCJ2BD(LatLng bd) { double x = bd.longitude, y = bd.latitude; double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * Math.PI); double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * Math.PI); double tempLon = z * Math.cos(theta) + 0.0065; double tempLat = z * Math.sin(theta) + 0.006; return new LatLng(tempLat, tempLon); }
业务需求
还是简单描述一下业务需求,点击一个地址或者按钮或者地图上的一个点,弹窗选择第三方地图导航,点击选择后调用第三方地图进行导航。
1,点击按钮弹窗选择
@OnClick({R.id.tv_navigation}) public void onViewClicked(View view) { switch (view.getId()) { ... case R.id.tv_navigation: showMapList(); break; } }
2,弹窗
private void showMapList() { final String[] mapNames = {"百度地图", "高德地图", "腾讯地图"}; final String[] packageNames = {"com.baidu.BaiduMap", "com.autonavi.minimap", "com.tencent.map"}; AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("请选择地图") .setItems(mapNames, (dialogInterface, i) -> { boolean installed = isInstalled(packageNames[i]); if (installed) { switch (i) { case 0: gotoBaiDuMap(); break; case 1: gotoGaoDeMap(); break; case 2: gotoTencentMap(); break; } } else { ToastUtil.showCenterToast(mapNames[i] + "未安装"); } }); builder.create().show(); }
调用之前判断一下是否安装:
/** * 检测所选地图是否安装 */ private boolean isInstalled(String packageName) { PackageManager manager = this.getPackageManager(); List<PackageInfo> installedPackages = manager.getInstalledPackages(0); if (installedPackages != null) { for (PackageInfo info : installedPackages) { if (info.packageName.equals(packageName)) return true; } } return false; }
3,调用地图
别忘了 申请权限。
百度地图
- 参数说明:
参数以字符串拼接的方式即可,这里用StringBuffer拼接,比String易读些。
- 调用示例:
private void gotoBaiDuMap() { // 驾车导航 StringBuffer sb = new StringBuffer("baidumap://map/navi") .append("?coord_type=gcj02") .append("&query=").append("长宁图书馆") .append("&src=").append(this.getPackageName()); Intent intent = new Intent(); intent.setData(Uri.parse(sb.toString())); startActivity(intent); }
高德地图
- 参数说明:
- 调用示例:
private void gotoGaoDeMap() { LatLng endPoint = BD2GCJ(new LatLng(31.220567, 121.395174));//转换坐标系 StringBuffer sb = new StringBuffer("androidamap://navi") .append("?sourceApplication=").append(getString(R.string.app_name)) .append("&lat=").append(endPoint.latitude) .append("&lon=").append(endPoint.longitude) .append("&dev=0"); Intent intent = new Intent(); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setPackage("com.autonavi.minimap"); intent.setData(Uri.parse(sb.toString())); startActivity(intent); }
腾讯地图
- 参数说明:
- 调用示例:
private void gotoTencentMap() { LatLng startPoint = BD2GCJ(new LatLng(mLatitude, mLongitude));//坐标转换 LatLng endPoint = BD2GCJ(new LatLng(31.220567, 121.395174));//坐标转换 StringBuffer sb = new StringBuffer("qqmap://map/routeplan") .append("?type=drive") .append("&from=我的位置") .append("&fromcoord=").append(startPoint.latitude).append(",").append(startPoint.longitude) .append("&to=长宁图书馆") .append("&tocoord=").append(endPoint.latitude).append(",").append(endPoint.longitude) .append("&referer=你的key"); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse(sb.toString())); startActivity(intent); }
注意,腾讯地图这里的from和to参数虽然可以省略,但是地图上就不显示地址了,默认是 地图上的点,而且referer参数需要申请开发者key。