2019超详细Android Studio新手开发百度地图(5)—百度地图_导航和TTS语音播报的实现
百度地图_导航和TTS语音播报的实现
前言
也是从小白一步步开始,很多资源感觉是很久以前的,而且没有操作配套截图,……遇到了很多坑,所以开发完成后决定重新写一份教程。
精力有限,尽可能详细,基本把每个步骤都配有对应的截图。
本文同本项目同步推进,已经是第三次建这样的项目,还是出了一些小问题,已经对应解决并附上解决方法,本文中所用到资源文件已经附上下载链接,也可以自行去百度地图开发者官网去下载,不过由于版本更新很快,若使用本文开发还是推荐使用本文链接进行下载。
相信按照本文可以解决绝大数问题,若还有其他问题,文末附上联系方式或者评论区冒泡。
注:
本文仅在前文的基础上只新增了步行导航和TTS语音播报。
参考官方文档(导航和TTS)步骤:
配置AndroidManifest.xml文件:
<!-- 读写sd卡 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 写sd卡 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.ACCESS_GPS"/> <!-- 获取精确gps位置 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <!-- 获取粗略位置 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <!-- 允许程序访问额外的定位提供者指令获取模拟定位信息 --> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/> <!-- 网络链接 --> <uses-permission android:name="android.permission.INTERNET"> </uses-permission> <!-- 获取网络状态 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"> </uses-permission> <!-- 更改wifi连状态 --> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <!-- 获取wifi状态 --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
布局更新:
<Button android:id="@+id/but_Navi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="导航" android:layout_marginLeft="0dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="209dp"/>
类包添加(导航资源包提取码:fxdm):
复制添加到java目录下:
报错处理:
直接删除,会自动引入正确的R;
若运行报如下错:
点击报错项,会自动跳转到有错误的代码处,也是上述处理即可;
这是缺少资源文件所致,添加如下资源文件:
已经提前处理,直接把上述文件夹对工程中相应文件夹进行覆盖即可:
build.gradle文件更新:
ndk { abiFilters "armeabi", "x86", "x86_64", "mips64", "mips" }
MainActivity文件更新(类包会自动导入):
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private MapView mMapView = null; private BaiduMap mBaiduMap = null; private Context context; //定位相关 private double mLatitude; private double mLongtitude; //方向传感器 private MyOrientationListener mMyOrientationListener; private float mCurrentX; //自定义图标 private BitmapDescriptor mIconLocation; private LocationClient mLocationClient; public BDAbstractLocationListener myListener; private LatLng mLastLocationData; private boolean isFirstin = true; // 路线规划相关 private RoutePlanSearch mSearch = null; //导航相关 private static final String APP_FOLDER_NAME = "MyBNDTSDK-Api"; private String mSDCardPath = null; private static final String[] authBaseArr = { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION }; private static final int authBaseRequestCode = 1; private boolean hasInitSuccess = false; static final String ROUTE_PLAN_NODE = "routePlanNode"; private BNRoutePlanNode mStartNode = null; private LatLng mDestLocationData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SDKInitializer.initialize(getApplicationContext()); setContentView(R.layout.activity_main); SDKInitializer.setCoordType(CoordType.BD09LL); this.context = this; mMapView = (MapView) findViewById(R.id.bmapView); //获取地图控件引用 mBaiduMap = mMapView.getMap(); initMyLocation(); initPoutePlan(); initLongClick(); button(); //初始化导航相关 if (initDirs()) { initNav 20000 i(); } } protected void onStart() { super.onStart(); //开启定位 mBaiduMap.setMyLocationEnabled(true); if (!mLocationClient.isStarted()) mLocationClient.start(); //开启方向传感器 mMyOrientationListener.start(); } @Override protected void onResume() { super.onResume(); mMapView.onResume(); } @Override protected void onPause() { super.onPause(); mMapView.onPause(); } @Override protected void onStop() { super.onStop(); //停止定位 mBaiduMap.setMyLocationEnabled(false); mLocationClient.stop(); //停止方向传感器 mMyOrientationListener.stop(); } @Override protected void onDestroy() { super.onDestroy(); mBaiduMap.setMyLocationEnabled(false); mMapView.onDestroy(); mMapView = null; mSearch.destroy(); } @Override public void onClick(View v) { SDKInitializer.initialize(getApplicationContext()); switch (v.getId()) { case R.id.but_Loc: { centerToMyLocation(mLatitude, mLongtitude); break; } case R.id.but_RoutrPlan: { StarRoute(); break; } case R.id.but_Navi: { if(mDestLocationData == null) { Toast.makeText(MainActivity.this, "导航:长按设置目标地点", Toast.LENGTH_SHORT).show(); return; } routeplanToNavi(); break; } } } //按钮响应 private void button() { //按钮 Button mbut_Loc = (Button) findViewById(R.id.but_Loc); Button mbut_RoutrPlan = (Button) findViewById(R.id.but_RoutrPlan); Button mbut_Navi = (Button) findViewById(R.id.but_Navi); //按钮处理 mbut_Loc.setOnClickListener(this); mbut_RoutrPlan.setOnClickListener(this); mbut_Navi.setOnClickListener(this); } //定位 private class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation location) { //mapView 销毁后不在处理新接收的位置 if (location == null || mMapView == null){ return; } MyLocationData locData = new MyLocationData.Builder() .accuracy(location.getRadius()) // 此处设置开发者获取到的方向信息,顺时针0-360 .direction(mCurrentX).latitude(location.getLatitude()) .longitude(location.getLongitude()).build(); mBaiduMap.setMyLocationData(locData); //设置自定义图标 MyLocationConfiguration config = new MyLocationConfiguration( MyLocationConfiguration.LocationMode.NORMAL, true, mIconLocation); mBaiduMap.setMyLocationConfiguration(config); //更新经纬度 mLatitude = location.getLatitude(); mLongtitude = location.getLongitude(); //设置起点 mLastLocationData = new LatLng(mLatitude, mLongtitude); if (isFirstin) { centerToMyLocation(location.getLatitude(), location.getLongitude()); if (location.getLocType() == BDLocation.TypeGpsLocation) { // GPS定位结果 Toast.makeText(context, "定位:"+location.getAddrStr(), Toast.LENGTH_SHORT).show(); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) { // 网络定位结果 Toast.makeText(context, "定位:"+location.getAddrStr(), Toast.LENGTH_SHORT).show(); } else if (location.getLocType() == BDLocation.TypeOffLineLocation) { // 离线定位结果 Toast.makeText(context, "定位:"+location.getAddrStr(), Toast.LENGTH_SHORT).show(); } else if (location.getLocType() == BDLocation.TypeServerError) { Toast.makeText(context, "定位:服务器错误", Toast.LENGTH_SHORT).show(); } else if (location.getLocType() == BDLocation.TypeNetWorkException) { Toast.makeText(context, "定位:网络错误", Toast.LENGTH_SHORT).show(); } else if (location.getLocType() == BDLocation.TypeCriteriaException) { Toast.makeText(context, "定位:手机模式错误,请检查是否飞行", Toast.LENGTH_SHORT).show(); } isFirstin = false; } } } //初始化定位 private void initMyLocation() { //缩放地图 MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(15.0f); mBaiduMap.setMapStatus(msu); //开启定位 mBaiduMap.setMyLocationEnabled(true); //声明LocationClient类 mLocationClient = new LocationClient(this); //通过LocationClientOption设置LocationClient相关参数 LocationClientOption option = new LocationClientOption(); option.setOpenGps(true); // 打开gps option.setCoorType("bd09ll"); // 设置坐标类型 option.setIsNeedAddress(true);//设置是否需要地址信息 option.setScanSpan(1000); //设置locationClientOption mLocationClient.setLocOption(option); myListener = new MyLocationListener(); //注册监听函数 mLocationClient.registerLocationListener(myListener); //初始化图标 mIconLocation = BitmapDescriptorFactory.fromResource(R.drawable.navi_map_gps); initOrientation(); //开始定位 mLocationClient.start(); } //回到定位中心 private void centerToMyLocation(double latitude, double longtitude) { mBaiduMap.clear(); mLastLocationData = new LatLng(latitude, longtitude); MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(mLastLocationData); mBaiduMap.animateMapStatus(msu); } //传感器 private void initOrientation() { //传感器 mMyOrientationListener = new MyOrientationListener(context); mMyOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() { @Override public void onOrientationChanged(float x) { mCurrentX = x; } }); } //路线规划初始化 private void initPoutePlan() { mSearch = RoutePlanSearch.newInstance(); mSearch.setOnGetRoutePlanResultListener(listener); } // 路线规划模块 public OnGetRoutePlanResultListener listener = new OnGetRoutePlanResultListener() { @Override public void onGetWalkingRouteResult(WalkingRouteResult result) { if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) { Toast.makeText(MainActivity.this, "路线规划:未找到结果,检查输入", Toast.LENGTH_SHORT).show(); //禁止定位 isFirstin = false; } assert result != null; if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) { // 起终点或途经点地址有岐义,通过以下接口获取建议查询信息 result.getSuggestAddrInfo(); return; } if (result.error == SearchResult.ERRORNO.NO_ERROR) { mBaiduMap.clear(); Toast.makeText(MainActivity.this, "路线规划:搜索完成", Toast.LENGTH_SHORT).show(); WalkingRouteOverlay overlay = new WalkingRouteOverlay(mBaiduMap); overlay.setData(result.getRouteLines().get(0)); overlay.addToMap(); overlay.zoomToSpan(); } //禁止定位 isFirstin = false; } @Override public void onGetTransitRouteResult(TransitRouteResult var1) { } @Override public void onGetMassTransitRouteResult(MassTransitRouteResult var1) { } @Override public void onGetDrivingRouteResult(DrivingRouteResult result) { } @Override public void onGetIndoorRouteResult(IndoorRouteResult var1) { } @Override public void onGetBikingRouteResult(BikingRouteResult var1) { } }; //开始规划 private void StarRoute() { SDKInitializer.initialize(getApplicationContext()); // 设置起、终点信息 PlanNode stNode = PlanNode.withCityNameAndPlaceName("北京", "西二旗地铁站"); PlanNode enNode = PlanNode.withCityNameAndPlaceName("北京", "百度科技园"); mSearch.walkingSearch((new WalkingRoutePlanOption()) .from(stNode) .to(enNode)); } //导航 //获取Sdcard目录 private String getSdcardDir() { if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) { return Environment.getExternalStorageDirectory().toString(); } return null; } //初始化导航目录 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; } private boolean hasBasePhoneAuth() { PackageManager pm = this.getPackageManager(); for (String auth : authBaseArr) { if (pm.checkPermission(auth, this.getPackageName()) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } //初始化语音播报 private void initTTS() { // 使用内置TTS BaiduNaviManagerFactory.getTTSManager().initTTS(getApplicationContext(), getSdcardDir(), APP_FOLDER_NAME, NormalUtils.getTTSAppID()); // 注册同步内置tts状态回调 BaiduNaviManagerFactory.getTTSManager().setOnTTSStateChangedListener( new IBNTTSManager.IOnTTSPlayStateChangedListener() { @Override public void onPlayStart() { Log.e("BNSDKDemo", "ttsCallback.onPlayStart"); } @Override public void onPlayEnd(String speechId) { Log.e("BNSDKDemo", "ttsCallback.onPlayEnd"); } @Override public void onPlayError(int code, String message) { Log.e("BNSDKDemo", "ttsCallback.onPlayError"); } } ); // 注册内置tts 异步状态消息 BaiduNaviManagerFactory.getTTSManager().setOnTTSStateChangedHandler( new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { Log.e("BNSDKDemo", "ttsHandler.msg.what=" + msg.what); } } ); } //初始化导航 private void initNavi() { // 申请权限 if (android.os.Build.VERSION.SDK_INT >= 23) { if (!hasBasePhoneAuth()) { this.requestPermissions(authBaseArr, authBaseRequestCode); return; } } BaiduNaviManagerFactory.getBaiduNaviManager().init(this, mSDCardPath, APP_FOLDER_NAME, new IBaiduNaviManager.INaviInitListener() { @Override public void onAuthResult(int status, String msg) { String result; if (0 == status) { result = "key校验成功!"; } else { result = "key校验失败, " + msg; } Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show(); } @Override public void initStart() { Toast.makeText(MainActivity.this, "导航引擎初始化开始", Toast.LENGTH_SHORT).show(); } @Override public void initSuccess() { Toast.makeText(MainActivity.this, "导航引擎初始化成功", Toast.LENGTH_SHORT).show(); hasInitSuccess = true; // 初始化tts initTTS(); } @Override public void initFailed() { Toast.makeText(MainActivity.this, "导航引擎初始化失败", Toast.LENGTH_SHORT).show(); } }); } //添加导航目的地图标 private void addDestInfoOverlay(LatLng latLng) { mBaiduMap.clear(); OverlayOptions options = new MarkerOptions().position(latLng) .icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_geo)) .zIndex(5); mBaiduMap.addOverlay(options); } //坐标转换 public static BDLocation bd2gcj(BDLocation loc) { return LocationClient.getBDLocationInCoorType(loc,BDLocation.BDLOCATION_BD09LL_TO_GCJ02); } //导航算路 private void routeplanToNavi() { final int coType = BNRoutePlanNode.CoordinateType.GCJ02; if (!hasInitSuccess) { Toast.makeText(MainActivity.this, "还未初始化!", Toast.LENGTH_SHORT).show(); } BDLocation srcBdLocation = new BDLocation(); srcBdLocation.setLatitude(mLastLocationData.latitude); srcBdLocation.setLongitude(mLastLocationData.longitude); BDLocation srcGcj = bd2gcj(srcBdLocation); BDLocation destBdLocation = new BDLocation(); destBdLocation.setLatitude(mDestLocationData.latitude); destBdLocation.setLongitude(mDestLocationData.longitude); BDLocation destGcj = bd2gcj(destBdLocation); BNRoutePlanNode sNode = new BNRoutePlanNode(srcGcj.getLongitude(),srcGcj.getLatitude(),"我的地点",null,coType); BNRoutePlanNode eNode = new BNRoutePlanNode(destGcj.getLongitude(),destGcj.getLatitude(),"目标地点",null,coType); mStartNode = sNode; 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, "导航:算路开始", Toast.LENGTH_SHORT) .show(); break; case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_SUCCESS: Toast.makeText(MainActivity.this, "导航:算路成功", Toast.LENGTH_SHORT) .show(); break; case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_FAILED: Toast.makeText(MainActivity.this, "导航:算路失败", Toast.LENGTH_SHORT) .show(); break; case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_TO_NAVI: Toast.makeText(MainActivity.this, "导航:算路成功准备进入导航", Toast.LENGTH_SHORT) .show(); Intent intent = new Intent(MainActivity.this, DemoGuideActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable(ROUTE_PLAN_NODE, mStartNode); intent.putExtras(bundle); startActivity(intent); break; default: // nothing break; } } }); } //长按处理 private void initLongClick() { mBaiduMap.setOnMapLongClickListener(new BaiduMap.OnMapLongClickListener() { @Override public void onMapLongClick(LatLng latLng) { Toast.makeText(context,"导航:设置目的地成功", Toast.LENGTH_LONG).show(); mDestLocationData = latLng; addDestInfoOverlay(latLng); } }); } }
在AndroidManifest.xml中声明定位的activity组件:
<activity android:name="com.sdkdemo.newif.DemoGuideActivity"/> <activity android:name="com.sdkdemo.liteapp.LiteActivity"/>
TTS语音激活(语音激活):
这里需要的是App ID
在MainActivity中找到如下代码处:
将鼠标移动到箭头所指的getTTSAppID()方法上,按住ctrl键,鼠标变成小手的形状左键点进去跳转到如下,把获取到的App ID输入即可:
此时导航和TTS语音播报也实现了,便可以运行了,效果如图:
长按地图设置目的地(下图西街商贸为目的地):
此时点击导航按钮(由于是晚上,自动暗色模式):
全览:
点击更多:
点击更多设置:
自点击导航键全程伴有TTS语音,图片无法演示,这里就不展示了。
工程源码本来也想百度网盘分享的,奈何得开会员才能上传,就放弃了……需要的朋友去下载吧,顺便赚个积分好了,……其实按照步骤是能自己建好自己工程项目的,几乎每个步骤都有截图的,或者不介意的朋友评论留下邮箱我给私发也行,每一部分我都留了备份,需要全部功能的朋友直接下载导航那一节的源码即可,有问题评论区回复,或者我的qq:1587128132,QQ邮箱:1587128132@qq.com。
源码:
定位
路线规划
导航
源码apk:apk 提取码:q8ey
- Android studio 百度地图开发(10)语音播报的问题:能正常导航,但是无法语音播报
- Android studio 百度地图开发(10)语音播报的问题:能正常导航,但是无法语音播报
- 实现百度地图导航Demo的语音播报功能
- android 百度地图导航TTS 语音播报没有声音
- iOS项目开发—TTS技术的实现即语音播报(实现方法一)
- iOS项目开发—TTS技术的实现即语音播报(实现方法一)
- 实现百度地图导航Demo的语音播报功能
- ios项目开发—TTS技术的实现即语音播报(实现方法二)
- iOS自带TTS技术的实现即语音播报
- 浅谈百度地图的简单开发最后收官之实现导航功能(五)
- 最详细的Android Studio百度地图(BaiduMap)开发教程,可以用作官方文档的教程!
- iOS自带文本转语音技术(TTS)的实现即语音播报的实践
- 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索...
- [置顶] Android 百度地图开发--- 导航功能输入起始地址实现导航,地址解析与反解析的使用
- 使用Android自带的TTS实现语音播报(电话号码)功能
- 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索
- Android Studio3.01获取高德地图百度地图开发版SHA1值和发布版SHA1值的史上最详细方法
- Android Studio建立百度地图步骤及导航无语音解决方法
- Android studio 百度地图开发(3)地图导航
- android 语音播报(通过手说tts 实现中文语音播报)