Android调起地图导航
想要使用导航功能可以使用各个地图的开放平台集成导航模块,如果不想集成也可以调起相关app导航
调起其他app首先得使用到该app包名,先贴出来
public final static String BAIDU_PACKAGENAME = "com.baidu.BaiduMap"; public final static String GAODE_PACKAGENAME = "com.autonavi.minimap"; public final static String TENCENT_PACKAGENAME = "com.tencent.map";
1.高德地图
/** * 高德导航 * @param context * @param location */ public static void gaodeGuide(Context context, double[] location) { if (isAvilible(context, GAODE_PACKAGENAME)) { try { Intent intent = Intent.getIntent("androidamap://navi?sourceApplication=" + context.getResources().getString(R.string.app_name) + "&poiname=我的目的地" + "&lat=" + location[0] + "&lon=" + location[1] + "&dev=0"); context.startActivity(intent); } catch (URISyntaxException e) { e.printStackTrace(); } } else { Toast.makeText(context, "您尚未安装高德地图", Toast.LENGTH_LONG).show(); Uri uri = Uri.parse("market://details?id=com.autonavi.minimap"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); context.startActivity(intent); } }
2.百度地图
/** * 百度导航 * @param context * @param location location[0]纬度lat,location[1]经度lon */ public static void baiduGuide(Context context, double[] location) { double[] baiduLoc = GpsUtils.gcj02_To_Bd09(location[0], location[1]); if (isAvilible(context, "com.baidu.BaiduMap")) {//传入指定应用包名 try { //intent = Intent.getIntent("intent://map/direction?origin=latlng:34.264642646862,108.95108518068|name:我家&destination=大雁塔&mode=driving®ion=西安&src=yourCompanyName|yourAppName#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end"); Intent intent = Intent.getIntent("intent://map/direction?" + //"origin=latlng:"+"34.264642646862,108.95108518068&" + //起点 此处不传值默认选择当前位置 "destination=latlng:" + baiduLoc[0] + "," + baiduLoc[1] + "|name:我的目的地" + //终点 "&mode=driving" + //导航路线方式 "®ion=" + // "&src=" + context.getResources().getString(R.string.app_name) + "#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end"); context.startActivity(intent); //启动调用 } catch (URISyntaxException e) { e.printStackTrace(); } } else {//未安装 //market为路径,id为包名 //显示手机上所有的market商店 Toast.makeText(context, "您尚未安装百度地图", Toast.LENGTH_LONG).show(); Uri uri = Uri.parse("market://details?id=com.baidu.BaiduMap"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); context.startActivity(intent); } }
3.腾讯地图
/** * 腾讯导航 * @param context * @param location */ public static void tencentGuide(Context context, double[] location) { String downloadUri = "http://softroute.map.qq.com/downloadfile?cid=00001"; String baseUrl = "qqmap://map/"; String searchPlace = "search?keyword=酒店&bound=39.907293,116.368935,39.914996,116.379321"; String searchAround = "search?keyword=肯德基¢er=39.908491,116.374328&radius=1000"; String busPlan = "routeplan?type=bus&from=我的家&fromcoord=39.980683,116.302&to=柳巷&tocoord=39.9836,116.3164&policy=2"; String drivePlan = "routeplan?type=drive&from=&fromcoord=&to=&tocoord=" + location[0] + "," + location[1] + "&policy=1"; String tencnetUri = baseUrl + drivePlan + "&referer=" + context.getResources().getString(R.string.app_name); if (isAvilible(context, TENCENT_PACKAGENAME)) { Intent intent; try { intent = Intent.parseUri(tencnetUri, 0); context.startActivity(intent); } catch (URISyntaxException e) { e.printStackTrace(); } } else { //直接下载 // Intent intent; // try { // intent = Intent.parseUri(downloadUri, 0); // context.startActivity(intent); // } catch (URISyntaxException e) { // e.printStackTrace(); // } //市场下载 Toast.makeText(context, "您尚未安装腾讯地图", Toast.LENGTH_LONG).show(); Uri uri = Uri.parse("market://details?id=" + TENCENT_PACKAGENAME); Intent intent = new Intent(Intent.ACTION_VIEW, uri); context.startActivity(intent); } }
在使用的时候需要先检查是否安装了该app
/** * 检查手机上是否安装了指定的软件 * * @param context * @param packageName:应用包名 * @return */ public static boolean isAvilible(Context context, String packageName) { //获取packagemanager final PackageManager packageManager = context.getPackageManager(); //获取所有已安装程序的包信息 List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0); //用于存储所有已安装程序的包名 List<String> packageNames = new ArrayList<String>(); //从pinfo中将包名字逐一取出,压入pName list中 if (packageInfos != null) { for (int i = 0; i < packageInfos.size(); i++) { String packName = packageInfos.get(i).packageName; packageNames.add(packName); } } //判断packageNames中是否有目标程序的包名,有TRUE,没有FALSE return packageNames.contains(packageName); }
调起导航的方法是较为固定的,没啥要说的,这里尤其是想说一下坐标系的问题。
在实际使用过程中发现了百度和其他地图的经纬度使用的时候有偏差的问题,这里是因为百度和其他地图使用了不同的坐标系:
-
WGS-84原始坐标系,一般用国际GPS纪录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的经纬度(国外)都是基于WGS-84坐标系的;
但是在国内是不允许直接用WGS84坐标系标注的,必须经过加密后才能使用; -
GCJ-02坐标系,又名“火星坐标系”,是我国国测局独创的坐标体系,由WGS-84加密而成,在国内,必须至少使用GCJ-02坐标系,
或者使用在GCJ-02加密后再进行加密的坐标系,如百度坐标系。高德和Google在国内都是使用GCJ-02坐标系,可以说,GCJ-02是国内最广泛使用的坐标系; -
百度坐标系:bd-09,百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系,只适用于百度地图。
由于存在火星坐标差异,我们只能把坐标转换成统一的坐标才能够正确使用,转换方法也是有现成的工具方法的:
public class GpsUtils { public static double pi = 3.1415926535897932384626; public static double x_pi = 3.14159265358979324 * 3000.0 / 180.0; public static double a = 6378245.0; public static double ee = 0.00669342162296594323; public static double transformLat(double x, double y) { double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; return ret; } public static double transformLon(double x, double y) { double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; return ret; } public static double[] transform(double lat, double lon) { if (outOfChina(lat, lon)) { return new double[]{lat, lon}; } double dLat = transformLat(lon - 105.0, lat - 35.0); double dLon = transformLon(lon - 105.0, lat - 35.0); double radLat = lat / 180.0 * pi; double magic = Math.sin(radLat); magic = 1 - ee * magic * magic; double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); double mgLat = lat + dLat; double mgLon = lon + dLon; return new double[]{mgLat, mgLon}; } public static boolean outOfChina(double lat, double lon) { if (lon < 72.004 || lon > 137.8347) return true; if (lat < 0.8293 || lat > 55.8271) return true; return false; } /** * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System * * @param lat * @param lon * @return */ public static double[] gps84_To_Gcj02(double lat, double lon) { if (outOfChina(lat, lon)) { return new double[]{lat, lon}; } double dLat = transformLat(lon - 105.0, lat - 35.0); double dLon = transformLon(lon - 105.0, lat - 35.0); double radLat = lat / 180.0 * pi; double magic = Math.sin(radLat); magic = 1 - ee * magic * magic; double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); double mgLat = lat + dLat; double mgLon = lon + dLon; return new double[]{mgLat, mgLon}; } /** * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return */ public static double[] gcj02_To_Gps84(double lat, double lon) { double[] gps = transform(lat, lon); double lontitude = lon * 2 - gps[1]; double latitude = lat * 2 - gps[0]; return new double[]{latitude, lontitude}; } /** * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标 * * @param lat * @param lon */ public static double[] gcj02_To_Bd09(double lat, double lon) { double x = lon, y = lat; double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi); double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi); double tempLon = z * Math.cos(theta) + 0.0065; double tempLat = z * Math.sin(theta) + 0.006; double[] gps = {tempLat, tempLon}; return gps; } /** * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * @param lat * @param lon * @return */ public static double[] bd09_To_Gcj02(double lat, double lon) { double x = lon - 0.0065, y = lat - 0.006; double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi); double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi); double tempLon = z * Math.cos(theta); double tempLat = z * Math.sin(theta); double[] gps = {tempLat, tempLon}; return gps; } /** * 将gps84转为bd09 * * @param lat * @param lon * @return */ public static double[] gps84_To_bd09(double lat, double lon) { double[] gcj02 = gps84_To_Gcj02(lat, lon); double[] bd09 = gcj02_To_Bd09(gcj02[0], gcj02[1]); return bd09; } public static double[] bd09_To_gps84(double lat, double lon) { double[] gcj02 = bd09_To_Gcj02(lat, lon); double[] gps84 = gcj02_To_Gps84(gcj02[0], gcj02[1]); //保留小数点后六位 gps84[0] = retain6(gps84[0]); gps84[1] = retain6(gps84[1]); return gps84; } /** * 保留小数点后六位 * * @param num * @return */ private static double retain6(double num) { String result = String.format("%.6f", num); return Double.valueOf(result); } }
在使用的时候把不同的坐标系转换成需要的坐标系再传入就可以正确使用了
by jungle张轶