开箱即用 Android常用导航使用封装

374 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

Android跳转到第三方导航工具封装

现在基于位置的服务已经越来越完善,涉及到导航的功能也越来越多,常用的平台为谷歌地图,百度地图,高德地图。

开发中常用的导航分为两种类型,一种是内置地图SDK,调用SDK的导航方法,直接应用内导航,无需跳转到第三方的应用。缺点是如果该地图位置不齐全或者导航不精准,用户无法控制自己想要的哪一个厂商的导航功能。我们不可能集成所有的导航SDK。

另一种类型是判断用户手机中安装的地图软件,如果存在就弹窗让用户选择哪一个导航。目前微信的位置分享点击导航也是基于这个实现。如用户安装了百度地图,会弹出让用户选择腾讯地图还是百度地图,如果选择百度地图则会跳转到百度地图App的导航页面。

比较实用的方式是我们判断是否安装了导航。如果没有安装地图App,那么就跳转到百度的路径规划页面,如果安装了地图App,就跳转到指定的地图导航

比如百度地图的SDK导航

 @Override
    protected void init() {
        initView();
        //初始化百度地图的初始位置和状态
        initBaiduMap();
        initListener();
    }

    private void initListener() {
        mIvBack.setOnClickListener(this);
        mIvNavigationIcon.setOnClickListener(this);
    }

    //开启导航
    private void navigate2Location() {

        // 获取导航控制类
        BikeNavigateHelper.getInstance().initNaviEngine(this, new IBEngineInitListener() {
            @Override
            public void engineInitSuccess() {
                //骑行导航初始化成功之后的回调
                LogUtil.w("骑行导航初始化成功");

                //起终点位置
                LatLng endPt = new LatLng(30.61548699999999, 114.254961);
                //构造BikeNaviLaunchParam
                //.vehicle(0)默认的普通骑行导航
                BikeNaviLaunchParam param = new BikeNaviLaunchParam().stPt(mMyLatLng).endPt(endPt).vehicle(0);

                //发起算路
                BikeNavigateHelper.getInstance().routePlanWithParams(param, new IBRoutePlanListener() {
                    @Override
                    public void onRoutePlanStart() {
                        //执行算路开始的逻辑
                    }

                    @Override
                    public void onRoutePlanSuccess() {
                        //算路成功
                        //跳转至导航页面
                        Intent intent = new Intent(mActivity, BNaviGuideActivity.class);
                        startActivity(intent);
                    }

                    @Override
                    public void onRoutePlanFail(BikeRoutePlanError bikeRoutePlanError) {
                        //执行算路失败的逻辑
                        ToastUtils.makeText(mActivity, "规划导航路径失败:" + bikeRoutePlanError.toString());
                    }
                });
            }

            @Override
            public void engineInitFail() {
                //骑行导航初始化失败之后的回调
                LogUtil.w("骑行导航初始化失败");
            }
        });

    }

    //路线规划
    private void initTTS() {
        mRouteSearch = RoutePlanSearch.newInstance();
        mRouteSearch.setOnGetRoutePlanResultListener(listener);

        PlanNode stNode = PlanNode.withLocation(mMyLatLng);
        PlanNode enNode = PlanNode.withLocation(new LatLng(30.61548699999999, 114.254961));
        mRouteSearch.bikingSearch((new BikingRoutePlanOption())
                .from(stNode)
                .to(enNode));
    }

    private void initBaiduMap() {

        //获取地图控制器
        mBaiduMap = mMapView.getMap();

        //隐藏比例按钮:隐藏缩放按钮
        mMapView.showScaleControl(false);
        mMapView.showZoomControls(false);

        //改变缩放值到17
        mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(17));
        //获取UI控制器,隐藏指南针:
        UiSettings uiSettings = mBaiduMap.getUiSettings();
        //不显示指南针
        uiSettings.setCompassEnabled(false);

        //设置自己的定位点的 模式-方向-icon
        MyLocationConfiguration configuration = new MyLocationConfiguration(
                MyLocationConfiguration.LocationMode.NORMAL, true, null
        );
        mBaiduMap.setMyLocationConfiguration(configuration);
        mBaiduMap.setMyLocationEnabled(true);

        //自己位置的定位初始化
        mLocationClient = new LocationClient(this);

        //通过LocationClientOption设置LocationClient相关参数
        LocationClientOption option = new LocationClientOption();
        option.setOpenGps(true); // 打开gps
        option.setCoorType("bd09ll"); // 设置坐标类型
        option.setScanSpan(1000);

        //设置locationClientOption
        mLocationClient.setLocOption(option);

        //注册LocationListener监听器
        MyLocationListener myLocationListener = new MyLocationListener();
        mLocationClient.registerLocationListener(myLocationListener);
        //开启地图定位图层
        mLocationClient.start();
    }

    @Override
    public void onNetworkConnectionChanged(boolean isConnected, NetWorkUtil.NetworkType networkType) {
    }

    @Override
    protected void dataObserver() {

    }

    private void initView() {
        mMapView = findViewById(R.id.bmapView);
        mTvTitle = findViewById(R.id.tv_title);
        mTvAddress = findViewById(R.id.tv_address);
        mIvNavigationIcon = findViewById(R.id.iv_navigation_icon);
        mIvBack = findViewById(R.id.iv_back);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.iv_back:
                mActivity.finish();
                break;
            case R.id.iv_navigation_icon:
                if (mMyLatLng != null) {
                    navigate2Location();
                }
                break;

        }
    }

    /**
     * 百度地图位置更新
     */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
//            LogUtil.e("获取到自己的位置信息:" + location.toString());
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null) {
                return;
            }

            mMyLatLng = new LatLng(location.getLatitude(), location.getLongitude());
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(location.getDirection())
                    .latitude(location.getLatitude())
                    .longitude(location.getLongitude())
                    .build();

            mBaiduMap.setMyLocationData(locData);

            if (!isMovedMyLocation) {
                //移动相机到指定的经纬度,只是第一次移动
                isMovedMyLocation = true;
                MapStatus.Builder builder = new MapStatus.Builder();
                builder.target(new LatLng(location.getLatitude(), location.getLongitude())).zoom(17.0f);
                mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));

                //初始化路线规划
                initTTS();
            }


            //添加指定的覆盖物
//            BitmapDescriptor searchBdA = BitmapDescriptorFactory.fromResource(R.drawable.ico_search);
//            MarkerOptions option = new MarkerOptions().icon(searchBdA).position(latLng);
//            mBaiduMap.addOverlay(option);

        }
    }

    /**
     * 路径规划的回调
     */
    OnGetRoutePlanResultListener listener = new OnGetRoutePlanResultListener() {

        @Override
        public void onGetWalkingRouteResult(WalkingRouteResult walkingRouteResult) {
        }

        @Override
        public void onGetTransitRouteResult(TransitRouteResult transitRouteResult) {
        }

        @Override
        public void onGetMassTransitRouteResult(MassTransitRouteResult massTransitRouteResult) {
        }

        @Override
        public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult) {
            //创建DrivingRouteOverlay实例
            DrivingRouteOverlay overlay = new DrivingRouteOverlay(mBaiduMap);
            if (drivingRouteResult != null && drivingRouteResult.getRouteLines().size() > 0) {
                //获取路径规划数据,(以返回的第一条路线为例)
                //为DrivingRouteOverlay实例设置数据
                overlay.setData(drivingRouteResult.getRouteLines().get(0));
                //在地图上绘制DrivingRouteOverlay
                overlay.addToMap();
            }
        }

        @Override
        public void onGetIndoorRouteResult(IndoorRouteResult indoorRouteResult) {
        }

        @Override
        public void onGetBikingRouteResult(BikingRouteResult bikingRouteResult) {

            if (bikingRouteResult != null && !CheckUtil.isEmpty(bikingRouteResult.getRouteLines())) {
                BikingRouteOverlay overlay = new BikingRouteOverlay(mBaiduMap);
                //获取路径规划数据,(以返回的第一条路线为例)
                //为DrivingRouteOverlay实例设置数据
                overlay.setData(bikingRouteResult.getRouteLines().get(0));
                //在地图上绘制DrivingRouteOverlay
                overlay.addToMap();
            }
        }

    };

    @Override
    protected void onResume() {
        mMapView.onResume();
        super.onResume();
    }

    @Override
    protected void onPause() {
        mMapView.onPause();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        mLocationClient.stop();
        mBaiduMap.setMyLocationEnabled(false);
        mMapView.onDestroy();
        mMapView = null;
        super.onDestroy();

        if (mRouteSearch != null)
            mRouteSearch.destroy();
    }

如果想直接进入导航:

 //开启导航
    private void navigate2Location() {

        // 获取导航控制类
        BikeNavigateHelper.getInstance().initNaviEngine(this, new IBEngineInitListener() {
            @Override
            public void engineInitSuccess() {
                //骑行导航初始化成功之后的回调
                LogUtil.w("骑行导航初始化成功");

                //起终点位置
                LatLng endPt = new LatLng(30.61548699999999, 114.254961);
                //构造BikeNaviLaunchParam
                //.vehicle(0)默认的普通骑行导航
                BikeNaviLaunchParam param = new BikeNaviLaunchParam().stPt(mMyLatLng).endPt(endPt).vehicle(0);

                //发起算路
                BikeNavigateHelper.getInstance().routePlanWithParams(param, new IBRoutePlanListener() {
                    @Override
                    public void onRoutePlanStart() {
                        //执行算路开始的逻辑
                    }

                    @Override
                    public void onRoutePlanSuccess() {
                        //算路成功
                        //跳转至导航页面
                        Intent intent = new Intent(mActivity, BNaviGuideActivity.class);
                        startActivity(intent);
                    }

                    @Override
                    public void onRoutePlanFail(BikeRoutePlanError bikeRoutePlanError) {
                        //执行算路失败的逻辑
                        ToastUtils.makeText(mActivity, "规划导航路径失败:" + bikeRoutePlanError.toString());
                    }
                });
            }

            @Override
            public void engineInitFail() {
                //骑行导航初始化失败之后的回调
                LogUtil.w("骑行导航初始化失败");
            }
        });

    }

另一种方式,跳转到地图App导航 地图APP判断和导航的工具类。

public class MapNavigationUtil {

    public final static String BAIDU_PKG = "com.baidu.BaiduMap"; //百度地图的包名
    public final static String GAODE_PKG = "com.autonavi.minimap";//高德地图的包名
    public final static String GOOGLE_PKG = "com.google.android.apps.maps";//谷歌地图的包名

    public static void openAMap(Context context, String endLat, String endLnt, String endAddress) {

        Intent intent = new Intent();
        intent.setAction("android.intent.action.VIEW");
        intent.setPackage(GAODE_PKG);
        intent.addCategory("android.intent.category.DEFAULT");

        intent.setData(Uri.parse("androidamap://route?sourceApplication=" + CommUtils.getString(R.string.app_name) +
//                "&dname=" + endAddress +
                "&dlat=" + endLat +
                "&dlon=" + endLnt +
                "&dev=0&t=4"
        ));

        context.startActivity(intent);
    }

    public static void openBaidu(Context context, String endLat, String endLnt, String endAddress) {
        Intent intent = new Intent();
        intent.setData(Uri.parse("baidumap://map/direction?region=0" +
                "&destination=" + endLat + "," + endLnt +
//                "&destination=name:" + endAddress + "|latlng:" + endLat + "," + endLnt +

                "&mode=walking"));

        context.startActivity(intent);

    }

    public static void openGoogle(Context context, String endLat, String endLnt, String endAddress) {
        Uri gmmIntentUri = Uri.parse("google.navigation:q="
                + endLat + "," + endLnt);
        Intent intent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
        intent.setPackage(GOOGLE_PKG);
        context.startActivity(intent);

    }

    /**
     * 检测地图应用是否安装
     */
    public static boolean checkMapAppsIsExist(Context context, String packagename) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(packagename, 0);
        } catch (Exception e) {
            packageInfo = null;
            e.printStackTrace();
        }
        if (packageInfo == null) {
            return false;
        } else {
            return true;
        }
    }

}

这里是集成了谷歌地图 百度地图 高德地图,在国内的话可以加上腾讯地图。类似的逻辑是一样的。设置对应的intent数据 跳转到指定App的指定页面

使用的方法如下:

    private void showNavigationPopup() {


            boolean googleMapEnable = MapNavigationUtil.checkMapAppsIsExist(mActivity, MapNavigationUtil.GOOGLE_PKG);
            boolean baiduMapEnable = MapNavigationUtil.checkMapAppsIsExist(mActivity, MapNavigationUtil.BAIDU_PKG);
            boolean aMapEnable = MapNavigationUtil.checkMapAppsIsExist(mActivity, MapNavigationUtil.GAODE_PKG);

            //只要有一个地图安装了就可以使用弹窗指示导航
            if (!googleMapEnable && !baiduMapEnable && !aMapEnable) {

                ToastUtils.get().makeText(mActivity, "You don't have any map apps installed");

            } else {

                mPopupView = new PopupView(mActivity)
                        .moveUpToKeyboard(false)
                        .hasShadowBg(true)
                        .dismissOnTouchOutside(true)
                        .autoDismiss(true)
                        .popupType(PopupType.Bottom)
                        .asCustom(new BottomMerchantNavigationPopup(mActivity,
                                mMerchantDetail.latStr, mMerchantDetail.longStr, mMerchantDetail.merchant_address,
                                googleMapEnable, baiduMapEnable, aMapEnable));

                if (mPopupView != null && !mPopupView.isShow()) {
                    mPopupView.show();
                }

            }

    }

效果:

弹窗选择:

百度地图:

高德地图:

谷歌地图需要谷歌服务和科学上网才可以使用,测试也是可以用的,这里就不放图了。

关于谷歌地图的使用,谷歌位置服务,谷歌定位坐标系如何在百度地图上展示,后面有时间会专门出一期。

这一块都是SDK和一些API的调用,不涉及到定位,坐标系之类的转换。不算复杂,希望对大家有帮助!