基于百度地图sdk的地图app开发——导航和模拟导航
Posted 今天也要努力搬砖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于百度地图sdk的地图app开发——导航和模拟导航相关的知识,希望对你有一定的参考价值。
这是基于百度地图sdk的地图app开发系列博客第七篇
代码仓库位置:https://github.com/YanhuiLu89/lmap.git
上一篇 基于百度地图sdk的地图app开发(六)——路线规划
因为本人是做C++开发,android和java都不熟,这方面知识有说错或者不好的习惯,欢迎赐较。
官方参考文档:Android导航SDK
一、工程配置
1.1 在AndroidMainfest.xml中加入以下权限
(指导文档里的权限比这多,前面几个权限在前面几篇文章里,使用百度地图sdk时已经加入了,所以这里只需要加下面这3个就好)
<!--获取Wi-Fi状态,避免产生不必要的网络请求 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 用于ugc事件上报拍照录像 -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 用于ugc事件上报录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
官方文档中授权key配置,在第一篇基于百度地图sdk的地图app开发(一)——开发环境配置与sdk下载里已经做了,所以下面直接到导航SDK核心集成
1.2 导航SDK集成和添加依赖库
将基于百度地图sdk的地图app开发(一)——开发环境配置与sdk下载中下载的onsdk_all.aar、和NaviTts.aar两个文件拷贝到app\\libs下,
在build.gradle中添加以下代码
android
// apache包
useLibrary 'org.apache.http.legacy'
……
dependencies
implementation files('libs\\\\NaviTts.aar')
implementation files('libs\\\\onsdk_all.aar')
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'android.arch.lifecycle:extensions:1.1.1'
1.3 TTS授权申请
SDK授权申请后,可以继续申请TTS授权。
1. 以基于百度地图sdk的地图app开发(一)——开发环境配置与sdk下载中提到的SDK授权申请时相同账号登录 http://yuyin.baidu.com/,点击右上角的“控制台“,进入控制台界面,点击左侧导航栏“语音技术”,然后点击创建应用。
2. 按步骤填入应用名称、包名等信息。
3. 点击立即创建会生成App ID,就是在开发中初始化TTS能力时传入的参数之一
至此,和导航SDK集成相关的授权申请就完成了。
虽然做了配置,导航没有声音原因目前未知
1.4so库的集成
在第一篇基于百度地图sdk的地图app开发(一)——开发环境配置与sdk下载中已经下载了so库(在arm64-v8a、armeabi和armeabi-v7a文件夹中),并且放置到了app/libs目录下
这里只需要在app的Build.gradle里增加以下红框中设置
另外也可以像官方文档中那样。在 main 目录下创建文件夹 jniLibs (如果有就不需要创建了),将下载文件的 armeabi 等相关文件夹复制到这个目录下,这时候就不需要上面红框的设置了。
1.5 Gradle配置
2为了避免Android "64K 引用限制"引起的异常,在app的build.gradle中需要引入multidex包,并进行相关配置,并且导航SDK内部使用了annotationProcessor,同样需要在build.gradle中配置,如下。
defaultConfig
……
// 避免"64K 引用限制"
multiDexEnabled true
// 导航SDK内部使用了annotationProcessor,需要添加下面代码,防止编译异常
javaCompileOptions annotationProcessorOptions includeCompileClasspath = true
二、导航SDK初始化
2.1、初始化导航sdk
导航sdk初始化接口详细说明
初始化接口init详细说明如:
/**
* 初始化百度导航.
*
* @param context 建议是应用的context
* @param sdcardRootPath 系统SD卡根目录路径
* @param appFolderName 应用在SD卡中的目录名
* @param naviInitListener 百度导航初始化监听器
*/
void init(final Context context,
final String sdcardRootPath,
final String appFolderName,
final INaviInitListener naviInitListener);
在MainActivity的OnCreate函数中添加以下代码进行初始化
//导航初始化
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在
if(sdCardExist)
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
BaiduNaviManagerFactory.getBaiduNaviManager().init(getApplicationContext(), sdDir.toString(), "lmap",
new IBaiduNaviManager.INaviInitListener()
@Override
public void onAuthResult(int i, String s)
if(i==0)
Toast.makeText(MainActivity.this, "key校验成功!", Toast.LENGTH_SHORT).show();
else if(i==1)
Toast.makeText(MainActivity.this, "key校验失败, " + s, Toast.LENGTH_SHORT).show();
@Override
public void initStart()
@Override
public void initSuccess()
Toast.makeText(MainActivity.this, "百度导航引擎初始化成功", Toast.LENGTH_SHORT).show();
// 初始化tts
initTTs();
@Override
public void initFailed(int i)
Toast.makeText(MainActivity.this, "百度导航引擎初始化失败", Toast.LENGTH_SHORT).show();
);
2.2 初始化tts
增加函数initTTs(),其调用时机为导航sdk初始化成功时调用,见上图initSuccess()接口中,其函数中先初始化,再 注册同步内置tts状态回调
private void initTTs()
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在
if(sdCardExist)
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
BNTTsInitConfig.Builder builder=new BNTTsInitConfig.Builder();
builder.context(getApplicationContext()).sdcardRootPath(sdDir.toString()).appFolderName("lmap").appId(("填入1.3步骤申请的app id"));
BaiduNaviManagerFactory.getTTSManager().initTTS( builder.build());
// 注册同步内置tts状态回调
BaiduNaviManagerFactory.getTTSManager().setOnTTSStateChangedListener(
new IBNTTSManager.IOnTTSPlayStateChangedListener()
@Override
public void onPlayStart()
Log.e("lmap", "ttsCallback.onPlayStart");
@Override
public void onPlayEnd(String speechId)
Log.e("lmap", "ttsCallback.onPlayEnd");
@Override
public void onPlayError(int code, String message)
Log.e("lmap", "ttsCallback.onPlayError");
);
三、增加导航功能入口
完成了一二步的配置和初始化,就可以开始使用导航功能了
3.1增加开始导航和模拟导航按钮
增加开始导航和模拟导航两个按钮,其布局代码如下
<LinearLayout
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_marginTop="630dp"
android:orientation="horizontal">
<Button
android:id="@+id/startnavi"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/banv_poi_search_text"
android:text="开始导航"
android:textSize="30sp"
android:visibility="gone" />
<Button
android:id="@+id/simnavi"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/banv_poi_search_text"
android:text="模拟导航"
android:textSize="30sp"
android:visibility="gone" />
</LinearLayout>
在上一章基于百度地图sdk的地图app开发(六)——路线规划,算路完成描画路线后,设置按钮可见,即在onGetDrivingRouteResult函数最后,添加以下代码
//显示开始导航按钮
Button startNav=findViewById(R.id.startnavi);
startNav.setVisibility(View.VISIBLE);
Button simNav=findViewById(R.id.simnavi);
simNav.setVisibility(View.VISIBLE);
算路完成显示效果如下
3.2开始导航和模拟导航按钮的响应函数中启动导航
我的本意是想使用上一章 基于百度地图sdk的地图app开发(六)——路线规划 算出来的路线结果DrivingRouteResult,来进行导航。客户点击选择哪条路线,就把哪条路线传给导航,开始导航。(我之前的开发经验大部分都是这样。)但是看IBNRoutePlanManager只接受点再重新算路,开始导航,并不接受DrivingRouteResult。所以只能画路线前,保存下来目的地,点击开始导航时再重新算一次。
实现步骤,在MainActivity中增加成员变量mDestation
private PoiInfo mDestation=null;
增加设置mDestation的接口
public void setDestation(PoiInfo poi)mDestation=poi;
在 上一章基于百度地图sdk的地图app开发(六)——路线规划提到的去这里按钮,点击函数中调用设置mDestation的接口
最后在开始导航按钮的click函数调用startNavi参数传true即启动真实导航,在模拟导航按钮的响应函数中调用startNavi,参数传false,即启动模拟导航。代码如下
//增加开始导航按钮的响应
Button startNav=findViewById(R.id.startnavi);
startNav.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
startNavi(true);
);
Button simNav=findViewById(R.id.simnavi);
simNav.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
startNavi(false);
);
startNavi接口的实现如下
private void startNavi(boolean isRealNavi)
if(mCurLocation==null||mDestation==null)
return;
BNRoutePlanNode sNode = new BNRoutePlanNode.Builder()
.latitude(mCurLocation.getLatitude())
.longitude(mCurLocation.getLongitude())
.name("我的位置")
.description("我的位置")
.build();
BNRoutePlanNode eNode = new BNRoutePlanNode.Builder()
.latitude(mDestation.getLocation().latitude)
.longitude(mDestation.getLocation().longitude)
.name(mDestation.name)
.description(mDestation.name)
.build();
List<BNRoutePlanNode> list = new ArrayList<>();
list.add(sNode);
list.add(eNode);
BaiduNaviManagerFactory.getRoutePlanManager().routePlanToNavi(
list,
IBNRoutePlanManager.RoutePlanPreference.ROUTE_PLAN_PREFERENCE_DEFAULT,
null,
new Handler(Looper.getMainLooper())
@Override
public void handleMessage(Message msg)
switch (msg.what)
case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_START:
Toast.makeText(MainActivity.this.getApplicationContext(),
"算路开始", Toast.LENGTH_SHORT).show();
break;
case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_SUCCESS:
Toast.makeText(MainActivity.this.getApplicationContext(),
"算路成功", Toast.LENGTH_SHORT).show();
break;
case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_FAILED:
Toast.makeText(MainActivity.this.getApplicationContext(),
"算路失败", Toast.LENGTH_SHORT).show();
break;
case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_TO_NAVI:
Toast.makeText(MainActivity.this.getApplicationContext(),
"算路成功准备进入导航", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MainActivity.this,
DemoGuideActivity.class);
intent.putExtra("isRealNavi",isRealNavi);
startActivity(intent);
break;
default:
// nothing
break;
);
以上“算路成功准备进入导航”用到的DemoGuideActivity在第4节部分实现
四、DemoGuideActivity的实现
新增Activity,继承自FragmentActivity(这一点很重要,如果按照默认继承自AppCompatActivity,在调用BaiduNaviManagerFactory.getRouteGuideManager().onCreate(this, config)会崩溃)。
4.1管理百度专业导航生命周期
在MainActivity的onCreate中调用RouteGuideManager的onCreate函数并将返回的view,设置成MainActivity的ContentView,代码如下
//管理专业导航生命周期
Bundle bundle = new Bundle();
// IS_REALNAVI代表导航类型,true表示真实导航,false表示模拟导航,默认是true
boolean isRealNavi=getIntent().getBooleanExtra("isRealNavi",true);
bundle.putBoolean(BNaviCommonParams.ProGuideKey.IS_REALNAVI,isRealNavi);
// IS_SUPPORT_FULL_SCREEN代表是否沉浸式,默认是true
bundle.putBoolean(BNaviCommonParams.ProGuideKey.IS_SUPPORT_FULL_SCREEN, true);
BNGuideConfig config = new BNGuideConfig.Builder().params(bundle).build();
View view=BaiduNaviManagerFactory.getRouteGuideManager().onCreate(this, config);
if (view != null)
setContentView(view);
在onStart、onResume、onPause、onStop、onDestroy接口中,分别增加以下代码
BaiduNaviManagerFactory.getRouteGuideManager().onStart();
BaiduNaviManagerFactory.getRouteGuideManager().onResume();
BaiduNaviManagerFactory.getRouteGuideManager().onPause();
BaiduNaviManagerFactory.getRouteGuideManager().onStop();
BaiduNaviManagerFactory.getRouteGuideManager().onDestroy(false);
4.2设置导航监听,增加结束导航处理
设置导航事件监听,在onNaviGuideEnd()中结束当前activity代码如下,其余接口暂时空实现
//设置导航事件监听
BaiduNaviManagerFactory.getRouteGuideManager().setNaviListener(new IBNaviListener()
//..其余一些空实现接口
@Override
public void onNaviGuideEnd()
finish();
);
设置导航view监听,在onNaviBackClick()内终止导航,其余接口空实现
//设置导航视图监听
BaiduNaviManagerFactory.getRouteGuideManager().setNaviViewListener(new IBNaviViewListener()
//。。。。一些空实现接口。。。。
@Override
public void onNaviBackClick()
BaiduNaviManagerFactory.getRouteGuideManager().stopNavi();
//。。。一些空实现接口。。。。。
);
程序效果,以下分别为真实导航、模拟导航、退出导航的效果
五、解决遇到的问题
5.1 jni接口找不到实现No implementation found for......
错误log如下
No implementation found for boolean com.baidu.navisdk.jni.nativeif.JNIGuidanceControl.SetRotateMode(int) (tried Java_com_baidu_navisdk_jni_nativeif_JNIGuidanceControl_SetRotateMode and Java_com_baidu_navisdk_jni_nativeif_JNIGuidanceControl_SetRotateMode__I)
at com.baidu.navisdk.jni.nativeif.JNIGuidanceControl.SetRotateMode(Native Method)
如果集成so库没有问题,出现这个问题多半是要更新库,我这里是更新库之后ok.
5.2 BaiduNaviManagerFactory.getRouteGuideManager().onCreate(this, config)崩溃
崩溃log如下
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.ViewGroup.findViewById(int)' on a null object reference
原因:DemoGuideActivity不能继承自AppCompatActivity
修改:改成public class DemoGuideActivity extends FragmentActivity ,崩溃问题解决
六、遗留问题没有声音
导航没有声音
以上是关于基于百度地图sdk的地图app开发——导航和模拟导航的主要内容,如果未能解决你的问题,请参考以下文章