标签:
Android studio 百度地图开发(3)地图导航
email:chentravelling@163.com
开发环境:win7 64位,Android Studio,请注意是Android Studio,使用的导航SDK版本:3.1.0。
地图显示、工程配置请参考:Android studio 百度地图开发(1)配置工程、显示地图
百度地图定位请参考:Android studio 百度地图开发(2)地图定位
因为在写定位功能时自己想从头到尾地写,但最后完全是参考了百度官网上的Demo才弄出来,后来发现用Android Studio做导航的资料太少了,于是这次写导航功能的时候就直接参考了百度Demo。但是问题依旧,开始使用了百度的RoutePlanDemo.java这个Demo,发现有几个包找不到,捣腾了很久没有成功,最后甚至准备用Myclipse试试,结果配置环境的时候还把MyEclipse玩坏了,重装!实在怀疑自己解决问题的能力,百般无奈之下,还是回到了Android Studio,静下心来分析问题出在了哪里:是不是本身SDK3.1.0里就没有这几个包了呢?果然,我打开jar包一看,没有。欣喜,换了导航SDK3.1.0中的Demo+SDK3.1.0,于是,导航就真正开始了。下面的代码都来自百度Demo,我只是自己理解了一番,后面将结合第二部分的地图定位和这部分的导航功能,自己再写一个可以实现手动选择起点和终点的Demo出来,喜欢吐槽的朋友请键盘留情,然后悄悄飘过吧。
一直以来都是喜欢百度的,尽管百度的的确确不能和Google比。但是,在中国的科技氛围里,我觉得百度已经够好了,所以也贴一点百度地图导航SDK的功能介绍。
最后,我想问问那些嘴里骂着百度心里又离不开百度的朋友:你为中国的科技、IT、社会做了什么?
二.导航SDK的应用
请注意:代码来自百度官方Demo。
导航SDK版本:BaiDuNaviSDK_3.1.0.jar和httpmime-4.1.2.jar
IDE:Android Studio
第一步:工程配置
这部分看似简单,没有关于Android Studio版的官方教程,真的很麻烦。
(1)将BaiDuNaviSDK_3.1.0.jar和httpmime-4.1.2.jar复制到/libs文件夹下;
(2)方法一:右键这两个jar包:add as library->确定;
方法二:打开build.gradle,在dependencies中增加:
compile files('libs/httpmime-4.1.2.jar') compile files('libs/BaiduNaviSDK_3.1.0.jar')
(4)在src/main/JNIlibs/armeabi和armeabi-v7a中都添加:libapp_BaiduNaviApplib.so、libapp_BaiduVIlib.so、libcurl.so、libgnustl_shared.so、 libbds.so、 libbd_etts.so 、libBDSpeechDecoder_V1.so
第二步:AndroidManifest.xml:增加权限、注册activity、API_KEY和定位服务
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="intvehapp.intvehapp" > <!-- 百度地图API所需权限 --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 访问精确位置的权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- SDK1.5需要android.permission.GET_TASKS权限判断本程序是否为当前运行的应用? --> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <!-- 来电消音 --> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 摄影机 --> <uses-permission android:name="android.permission.CAMERA" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".BNDemoMainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!--百度API_KEY--> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="iXDGdZtFiPifnNm6dUEFwDRXYQVeZ37V" /> <!--百度定位服务--> <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" > </service> <!--注册activity--> <activity android:name=".BNDemoGuideActivity" /> </application> </manifest>
package intvehapp.intvehapp; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import com.baidu.navisdk.adapter.BNOuterLogUtil; import com.baidu.navisdk.adapter.BNOuterTTSPlayerCallback; import com.baidu.navisdk.adapter.BNRoutePlanNode; import com.baidu.navisdk.adapter.BNRoutePlanNode.CoordinateType; import com.baidu.navisdk.adapter.BNaviSettingManager; import com.baidu.navisdk.adapter.BaiduNaviManager; import com.baidu.navisdk.adapter.BaiduNaviManager.NaviInitListener; import com.baidu.navisdk.adapter.BaiduNaviManager.RoutePlanListener; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class BNDemoMainActivity extends Activity { public static List<Activity> activityList = new LinkedList<Activity>(); /** * App在SD卡中的目录名 */ private static final String APP_FOLDER_NAME = "intvehapp"; /** * 4个按钮控件 */ private Button mWgsNaviBtn = null; private Button mGcjNaviBtn = null; private Button mBdmcNaviBtn = null; private Button mDb06ll = null; /** * SD卡的路径 */ private String mSDCardPath = null; public static final String ROUTE_PLAN_NODE = "routePlanNode"; public static final String SHOW_CUSTOM_ITEM = "showCustomItem"; public static final String RESET_END_NODE = "resetEndNode"; public static final String VOID_MODE = "voidMode"; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); activityList.add(this); setContentView(R.layout.activity_main_guide); /** * 获取按钮控件 */ mWgsNaviBtn = (Button) findViewById(R.id.wgsNaviBtn); mGcjNaviBtn = (Button) findViewById(R.id.gcjNaviBtn); mBdmcNaviBtn = (Button) findViewById(R.id.bdmcNaviBtn); mDb06ll = (Button) findViewById(R.id.mDb06llNaviBtn); BNOuterLogUtil.setLogSwitcher(true); /** * 初始化按钮监听函数 */ initListener(); if (initDirs()) { /** * 使用SDK前,先进行百度服务授权和引擎初始化。 */ initNavi(); } // BNOuterLogUtil.setLogSwitcher(true); } @Override protected void onResume() { super.onResume(); } /** * 为每一个按钮控件增加点击监听事件,增加算路节点 */ private void initListener() { if (mWgsNaviBtn != null) { mWgsNaviBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { /** * 判断百度导航是否初始化 */ if (BaiduNaviManager.isNaviInited()) { /** * 添加起点、终点 */ routeplanToNavi(CoordinateType.WGS84); } } }); } if (mGcjNaviBtn != null) { mGcjNaviBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if (BaiduNaviManager.isNaviInited()) { routeplanToNavi(CoordinateType.GCJ02); } } }); } if (mBdmcNaviBtn != null) { mBdmcNaviBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if (BaiduNaviManager.isNaviInited()) { routeplanToNavi(CoordinateType.BD09_MC); } } }); } if (mDb06ll != null) { mDb06ll.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if (BaiduNaviManager.isNaviInited()) { routeplanToNavi(CoordinateType.BD09LL); } } }); } } /** * 初始化SD卡,在SD卡路径下新建文件夹:App目录名,文件中包含了很多东西,比如log、cache等等 * @return */ private boolean initDirs() { mSDCardPath = getSdcardDir(); if (mSDCardPath == null) { return false; } File f = new File(mSDCardPath, APP_FOLDER_NAME); if (!f.exists()) { try { f.mkdir(); } catch (Exception e) { e.printStackTrace(); return false; } } return true; } String authinfo = null; /** * 内部TTS播报状态回传handler */ private Handler ttsHandler = new Handler() { public void handleMessage(Message msg) { int type = msg.what; switch (type) { case BaiduNaviManager.TTSPlayMsgType.PLAY_START_MSG: { showToastMsg("Handler : TTS play start"); break; } case BaiduNaviManager.TTSPlayMsgType.PLAY_END_MSG: { showToastMsg("Handler : TTS play end"); break; } default : break; } } }; /** * 内部TTS播报状态回调接口 */ private BaiduNaviManager.TTSPlayStateListener ttsPlayStateListener = new BaiduNaviManager.TTSPlayStateListener() { @Override public void playEnd() { // showToastMsg("TTSPlayStateListener : TTS play end"); } @Override public void playStart() { // showToastMsg("TTSPlayStateListener : TTS play start"); } }; public void showToastMsg(final String msg) { BNDemoMainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(BNDemoMainActivity.this, msg, Toast.LENGTH_SHORT).show(); } }); } /** * 使用SDK前,先进行百度服务授权和引擎初始化 */ private void initNavi() { BNOuterTTSPlayerCallback ttsCallback = null; BaiduNaviManager.getInstance().init(this, mSDCardPath, APP_FOLDER_NAME, new NaviInitListener() { @Override public void onAuthResult(int status, String msg) { if (0 == status) { authinfo = "key校验成功!"; } else { authinfo = "key校验失败, " + msg; } BNDemoMainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(BNDemoMainActivity.this, authinfo, Toast.LENGTH_LONG).show(); } }); } public void initSuccess() { Toast.makeText(BNDemoMainActivity.this, "百度导航引擎初始化成功", Toast.LENGTH_SHORT).show(); initSetting(); } public void initStart() { Toast.makeText(BNDemoMainActivity.this, "百度导航引擎初始化开始", Toast.LENGTH_SHORT).show(); } public void initFailed() { Toast.makeText(BNDemoMainActivity.this, "百度导航引擎初始化失败", Toast.LENGTH_SHORT).show(); } }, null, ttsHandler, null); } private String getSdcardDir() { if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) { return Environment.getExternalStorageDirectory().toString(); } return null; } /** * 算路设置起、终点,算路偏好,是否模拟导航等参数,然后在回调函数中设置跳转至诱导。 * @param coType */ private void routeplanToNavi(CoordinateType coType) { BNRoutePlanNode sNode = null; BNRoutePlanNode eNode = null; switch (coType) { case GCJ02: { sNode = new BNRoutePlanNode(116.30142, 40.05087, "百度大厦", null, coType); eNode = new BNRoutePlanNode(116.39750, 39.90882, "北京天安门", null, coType); break; } case WGS84: { sNode = new BNRoutePlanNode(116.300821, 40.050969, "百度大厦", null, coType); eNode = new BNRoutePlanNode(116.397491, 39.908749, "北京天安门", null, coType); break; } case BD09_MC: { sNode = new BNRoutePlanNode(12947471, 4846474, "百度大厦", null, coType); eNode = new BNRoutePlanNode(12958160, 4825947, "北京天安门", null, coType); break; } case BD09LL: { sNode = new BNRoutePlanNode(116.30784537597782, 40.057009624099436, "百度大厦", null, coType); eNode = new BNRoutePlanNode(116.40386525193937, 39.915160800132085, "北京天安门", null, coType); break; } default: ; } if (sNode != null && eNode != null) { List<BNRoutePlanNode> list = new ArrayList<BNRoutePlanNode>(); list.add(sNode); list.add(eNode); /** * 发起算路操作并在算路成功后通过回调监听器进入导航过程,返回是否执行成功 */ BaiduNaviManager .getInstance() .launchNavigator( this, //建议是应用的主Activity list, //传入的算路节点,顺序是起点、途经点、终点,其中途经点最多三个 1, //算路偏好 1:推荐 8:少收费 2:高速优先 4:少走高速 16:躲避拥堵 true, //true表示真实GPS导航,false表示模拟导航 new DemoRoutePlanListener(sNode)//开始导航回调监听器,在该监听器里一般是进入导航过程页面 ); } } /** * 导航回调监听器 */ public class DemoRoutePlanListener implements RoutePlanListener { private BNRoutePlanNode mBNRoutePlanNode = null; public DemoRoutePlanListener(BNRoutePlanNode node) { mBNRoutePlanNode = node; } @Override public void onJumpToNavigator() { /* * 设置途径点以及resetEndNode会回调该接口 */ for (Activity ac : activityList) { if (ac.getClass().getName().endsWith("BNDemoGuideActivity")) { return; } } /** * 导航activity */ Intent intent = new Intent(BNDemoMainActivity.this, BNDemoGuideActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable(ROUTE_PLAN_NODE, (BNRoutePlanNode) mBNRoutePlanNode); intent.putExtras(bundle); startActivity(intent); } @Override public void onRoutePlanFailed() { // TODO Auto-generated method stub Toast.makeText(BNDemoMainActivity.this, "算路失败", Toast.LENGTH_SHORT).show(); } } /** * 导航设置管理器 */ private void initSetting(){ /** * 日夜模式 1:自动模式 2:白天模式 3:夜间模式 */ BNaviSettingManager.setDayNightMode(BNaviSettingManager.DayNightMode.DAY_NIGHT_MODE_DAY); /** * 设置全程路况显示 */ BNaviSettingManager.setShowTotalRoadConditionBar(BNaviSettingManager.PreViewRoadCondition.ROAD_CONDITION_BAR_SHOW_ON); /** * 设置语音播报模式 */ BNaviSettingManager.setVoiceMode(BNaviSettingManager.VoiceMode.Veteran); /** * 设置省电模式 */ BNaviSettingManager.setPowerSaveMode(BNaviSettingManager.PowerSaveMode.DISABLE_MODE); /** * 设置实时路况条 */ BNaviSettingManager.setRealRoadCondition(BNaviSettingManager.RealRoadCondition.NAVI_ITS_ON); } private BNOuterTTSPlayerCallback mTTSCallback = new BNOuterTTSPlayerCallback() { @Override public void stopTTS() { // TODO Auto-generated method stub Log.e("test_TTS", "stopTTS"); } @Override public void resumeTTS() { // TODO Auto-generated method stub Log.e("test_TTS", "resumeTTS"); } @Override public void releaseTTSPlayer() { // TODO Auto-generated method stub Log.e("test_TTS", "releaseTTSPlayer"); } @Override public int playTTSText(String speech, int bPreempt) { // TODO Auto-generated method stub Log.e("test_TTS", "playTTSText" + "_" + speech + "_" + bPreempt); return 1; } @Override public void phoneHangUp() { // TODO Auto-generated method stub Log.e("test_TTS", "phoneHangUp"); } @Override public void phoneCalling() { // TODO Auto-generated method stub Log.e("test_TTS", "phoneCalling"); } @Override public void pauseTTS() { // TODO Auto-generated method stub Log.e("test_TTS", "pauseTTS"); } @Override public void initTTSPlayer() { // TODO Auto-generated method stub Log.e("test_TTS", "initTTSPlayer"); } @Override public int getTTSState() { // TODO Auto-generated method stub Log.e("test_TTS", "getTTSState"); return 1; } }; }
package intvehapp.intvehapp; import java.util.ArrayList; import java.util.List; import com.baidu.navisdk.adapter.BNRouteGuideManager; import com.baidu.navisdk.adapter.BNRouteGuideManager.CustomizedLayerItem; import com.baidu.navisdk.adapter.BNRouteGuideManager.OnNavigationListener; import com.baidu.navisdk.adapter.BNRoutePlanNode; import com.baidu.navisdk.adapter.BNaviBaseCallbackModel; import com.baidu.navisdk.adapter.BaiduNaviCommonModule; import com.baidu.navisdk.adapter.NaviModuleFactory; import com.baidu.navisdk.adapter.NaviModuleImpl; import com.baidu.navisdk.adapter.BNRoutePlanNode.CoordinateType; import android.app.Activity; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; /** * 诱导界面 * * @author sunhao04 * */ public class BNDemoGuideActivity extends Activity { private final String TAG = BNDemoGuideActivity.class.getName(); private BNRoutePlanNode mBNRoutePlanNode = null; private BaiduNaviCommonModule mBaiduNaviCommonModule = null; /* * 对于导航模块有两种方式来实现发起导航。 1:使用通用接口来实现 2:使用传统接口来实现 */ // 是否使用通用接口 private boolean useCommonInterface = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); BNDemoMainActivity.activityList.add(this); createHandler(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { } View view = null; if (useCommonInterface) { //使用通用接口 mBaiduNaviCommonModule = NaviModuleFactory.getNaviModuleManager().getNaviCommonModule( NaviModuleImpl.BNaviCommonModuleConstants.ROUTE_GUIDE_MODULE, this, BNaviBaseCallbackModel.BNaviBaseCallbackConstants.CALLBACK_ROUTEGUIDE_TYPE, mOnNavigationListener); if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onCreate(); view = mBaiduNaviCommonModule.getView(); } } else { //使用传统接口 view = BNRouteGuideManager.getInstance().onCreate(this,mOnNavigationListener); } if (view != null) { setContentView(view); } Intent intent = getIntent(); if (intent != null) { Bundle bundle = intent.getExtras(); if (bundle != null) { mBNRoutePlanNode = (BNRoutePlanNode) bundle.getSerializable(BNDemoMainActivity.ROUTE_PLAN_NODE); } } } @Override protected void onResume() { super.onResume(); if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onResume(); } } else { BNRouteGuideManager.getInstance().onResume(); } if (hd != null) { hd.sendEmptyMessageAtTime(MSG_SHOW, 2000); } } protected void onPause() { super.onPause(); if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onPause(); } } else { BNRouteGuideManager.getInstance().onPause(); } }; @Override protected void onDestroy() { super.onDestroy(); if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onDestroy(); } } else { BNRouteGuideManager.getInstance().onDestroy(); } BNDemoMainActivity.activityList.remove(this); } @Override protected void onStop() { super.onStop(); if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onStop(); } } else { BNRouteGuideManager.getInstance().onStop(); } } @Override public void onBackPressed() { if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onBackPressed(false); } } else { BNRouteGuideManager.getInstance().onBackPressed(false); } } public void onConfigurationChanged(android.content.res.Configuration newConfig) { super.onConfigurationChanged(newConfig); if(useCommonInterface) { if(mBaiduNaviCommonModule != null) { mBaiduNaviCommonModule.onConfigurationChanged(newConfig); } } else { BNRouteGuideManager.getInstance().onConfigurationChanged(newConfig); } }; private void addCustomizedLayerItems() { List<CustomizedLayerItem> items = new ArrayList<CustomizedLayerItem>(); CustomizedLayerItem item1 = null; if (mBNRoutePlanNode != null) { item1 = new CustomizedLayerItem(mBNRoutePlanNode.getLongitude(), mBNRoutePlanNode.getLatitude(), mBNRoutePlanNode.getCoordinateType(), getResources().getDrawable(R.drawable.ic_launcher), CustomizedLayerItem.ALIGN_CENTER); items.add(item1); BNRouteGuideManager.getInstance().setCustomizedLayerItems(items); } BNRouteGuideManager.getInstance().showCustomizedLayer(true); } private static final int MSG_SHOW = 1; private static final int MSG_HIDE = 2; private static final int MSG_RESET_NODE = 3; private Handler hd = null; private void createHandler() { if (hd == null) { hd = new Handler(getMainLooper()) { public void handleMessage(android.os.Message msg) { if (msg.what == MSG_SHOW) { addCustomizedLayerItems(); } else if (msg.what == MSG_HIDE) { BNRouteGuideManager.getInstance().showCustomizedLayer(false); } else if (msg.what == MSG_RESET_NODE) { BNRouteGuideManager.getInstance().resetEndNodeInNavi( new BNRoutePlanNode(116.21142, 40.85087, "百度大厦11", null, CoordinateType.GCJ02)); } }; }; } } private OnNavigationListener mOnNavigationListener = new OnNavigationListener() { @Override public void onNaviGuideEnd() { finish(); } @Override public void notifyOtherAction(int actionType, int arg1, int arg2, Object obj) { if (actionType == 0) { Log.i(TAG, "notifyOtherAction actionType = " + actionType + ",导航到达目的地!"); } Log.i(TAG, "actionType:" + actionType + "arg1:" + arg1 + "arg2:" + arg2 + "obj:" + obj.toString()); } }; }
三.个人理解
目前Run起来后还有点问题,比如还没发现语音播报这个可不可以。
单从这个Demo来看,导航功能实现起来并不会复杂,百度服务授权和引擎初始化成功后,主要是传入起点、终点、途经点等需要计算的节点,然后在回调函数中进入导航回调监听器,然后进入诱导界面。后面还有很多地方可以个性化修改或者按照自己的需要进行功能完善,这便是后面我需要做的工作了。
可能第一次用Android Studio做百度地图真的会遇到不少问题,比如SDK版本和.so文件(需要添加到armeabi和armeabi-v7a文件夹中)总之,不管多难,不要轻易放弃,问题始终是可以解决的。
标签:
原文地址:http://blog.csdn.net/chentravelling/article/details/51012420