想要使用導航功能可以使用各個地圖的開放平台集成導航模塊,如果不想集成也可以調起相關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張軼