近期做了一个地图的项目,需要用到实时导航,在网上查找百度地图实时导航在RN中的组件没有找到,于是就自己写了一个方法可以调用原生的实时导航。
一、首先得用Android原生先实现实时导航
1、从网上下载实例Demo
http://lbsyun.baidu.com/index.php?title=android-navsdk/navsdk-android-download
下载完成后解压发现名为BaiduNavi_AndroidSDK_v3.3.1_Sample.zip的压缩包才是实时导航的Demo,将该压缩包解压问题来了,官网所给的Demo并没有Android Studio,而最后写RN和Android原生的结合必须得用Android Studio,因此第二步需要做的就是将官网例子写为Android Studio可以运行的。
2、将Demo在Android Studio中运行起来
① 用Android Studio新建一个项目名为BaiduNavDemo的应用。
② 将官网所给的例子BaiduNaviSDKSimpleDemo中的内容有选择的复制到BaiduNavDemo的项目中。
1) 将示例中的assets文件夹复制到BaiduNavDemo\app\src\main文件夹下面。
2) 将libs文件夹中的4个jar包复制到项目的libs中并且选中所有jar包右键选择Add As Library。
3) 在BaiduNavDemo的项目中app\src\main文件夹下面新建jnilibs文件夹,将armeabi文件夹中的so文件复制到jniLib文件夹下面的armeabi-v7a文件夹下面。
4) 将res文件夹中的内容复制到res文件夹中,strings.xml文件中复制完后修改app_name,styles.xml文件中完全复制,activity_main.xml文件也是全部复制。
5) 将src中的4个Java文件复制到项目的Java文件夹下,将4个Java文件逐个打开将报红错的地方改正。
③ 为了方便起见直接将MainActivity.java这个主文件作为导航的初始页,将BNDemoMainActivity.java文件中的内容复制到MainActivity.java文件中,这样会报一些红错, 解决这些错误将BNDemoMainActivity改为MainActivity即可。
除此之外,还要将BNDemoGuideActivity.java文件中的红错解决,就是用MainActivity替换BNDemoMainActivity即可。activity_main.xml文件中改为MainActivity
AndroidManifest.xml文件中加入以下内容:
<!-- 手机震动权限 -->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCES_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_GPS" />
<!-- 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" />
<!--百度API_KEY-->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="自己的key" />
<!--百度定位服务-->
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
<!--注册activity-->
<activity android:name=".BNDemoGuideActivity" />
④ 此时需要在百度地图api官网上申请key和语音播报的appid
将申请好的应用AK值写在
<meta-data android:name="com.baidu.lbsapi.API_KEY"
android:value="8nqGEdwqbkTirosEClpUVmbuFbp7X79c" />
在http://yuyin.baidu.com/app网址上为自己的应用开通语音合成功能,并将appid写在
private void initSetting() {
// 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);
BNaviSettingManager.setIsAutoQuitWhenArrived(true);
Bundle bundle = new Bundle();
// 必须设置APPID,否则会静音
bundle.putString(BNCommonSettingParam.TTS_APP_ID, "9354030");
BNaviSettingManager.setNaviSdkParam(bundle);
}
提示:获取发布版的SHA1和开发版的SHA1参照 http://jingyan.baidu.com/article/25648fc19932849191fd0001.html 此时就可以用Android Studio运行官网上的Demo了。
二、在react-native项目中直接实现点击导航按钮进入导航页面
1、初始化一个RN项目,并且调用原生Android的方法。
这一步在上一篇文章中react-native调用Android原生方法中已经详细说明。以下步骤是在此基础上操作的。
2、用Android studio打开rnAndroid项目下的android文件夹。
3、复制官方实时导航中的项目
1) assets文件夹含内容复制到app/src/main下
2) android目录下新建libs文件夹并复制导航项目中的libs文件夹下的jar包,并且选中所有jar包右键选择Add As Library对话框选择app
3) 在项目中app\src\main文件夹下面新建jnilibs文件夹,将armeabi文件夹中的so文件复制到jniLib文件夹下面的armeabi-v7a文件夹下面。
4) 将res文件夹中的内容复制到res文件夹中,strings.xml文件中复制完后修改app_name,styles.xml文件中只复制不同的地方,activity_main.xml文件也是全部复制。
5) 在java下的com.rnandroid包下新建nav文件夹用来放java文件,将src中的4个Java文件复制到项目的nav文件夹下,将4个Java文件逐个打开将报红错的地方改正。4、将BNDemoMainActivity中的内容移接到MainActivity中
1) 将BNDemoMainActivity中的代码复制到MainActivity中(只复制代码,会自动提示引包的),修改报的红错。
先将MainActivity中的最后一行代码注释掉,(先测一下是否可以运行再实现RN直接调用)
// @Override
// protected String getMainComponentName() {
// return "rnAndroid";
// }
activity_main.xml文件中改为MainActivity
2) AndroidManifest.xml文件中加入内容和上面一样。
AndroidManifest.xml中注册activity时注意包名。
<!--注册activity-->
<activity android:name="com.rnandroid.nav.BNDemoGuideActivity" />
3) 在百度地图api官网上申请key和语音播报的appid,注意填写的包名是AndroidManifest.xml中package后面的包名
package="com.rnandroid"
5、此时运行可以正常的调出来导航,下面实现在RN中直接调出来导航。
① 将MainActivity中注释掉的最后一行代码取消注释。
② 将RnTest.java文件中代码改为
public class RnTest extends ReactContextBaseJavaModule {
private ReactApplicationContext context = null;//添加
public static List<Activity> activityList = new LinkedList<Activity>();//添加
public static final String ROUTE_PLAN_NODE = "routePlanNode";//添加
public RnTest(ReactApplicationContext reactContext) {
super(reactContext);
context = reactContext;//添加
}
//添加的导航内容开始
private void routeplanToNavi(BNRoutePlanNode.CoordinateType coType) {
// mCoordinateType = coType;
// if (!hasInitSuccess) {
// Toast.makeText(MainActivity.this, "还未初始化!", Toast.LENGTH_SHORT).show();
// }
// // 权限申请
// if (android.os.Build.VERSION.SDK_INT >= 23) {
// // 保证导航功能完备
// if (!hasCompletePhoneAuth()) {
// if (!hasRequestComAuth) {
// hasRequestComAuth = true;
// this.requestPermissions(authComArr, authComRequestCode);
// return;
// } else {
// Toast.makeText(MainActivity.this, "没有完备的权限!", Toast.LENGTH_SHORT).show();
// }
// }
//
// }
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, list, 1, true, new DemoRoutePlanListener(sNode));
BaiduNaviManager.getInstance().launchNavigator(this.getCurrentActivity(), list, 1, true, new DemoRoutePlanListener(sNode,this.getCurrentActivity()),eventListerner);
}
}
BaiduNaviManager.NavEventListener eventListerner = new BaiduNaviManager.NavEventListener() {
@Override
public void onCommonEventCall(int what, int arg1, int arg2, Bundle bundle) {
BNEventHandler.getInstance().handleNaviEvent(what, arg1, arg2, bundle);
}
};
public class DemoRoutePlanListener implements BaiduNaviManager.RoutePlanListener {
private BNRoutePlanNode mBNRoutePlanNode = null;
private Activity _currentActivity =null;
public DemoRoutePlanListener(BNRoutePlanNode node , Activity currentActivity) {
mBNRoutePlanNode = node;
_currentActivity =currentActivity;
}
@Override
public void onJumpToNavigator() {
/*
* 设置途径点以及resetEndNode会回调该接口
*/
for (Activity ac : activityList) {
if (ac.getClass().getName().endsWith("BNDemoGuideActivity")) {
return;
}
}
Intent intent = new Intent(_currentActivity, BNDemoGuideActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(ROUTE_PLAN_NODE, (BNRoutePlanNode) mBNRoutePlanNode);
intent.putExtras(bundle);
_currentActivity.startActivity(intent);
}
@Override
public void onRoutePlanFailed() {
// TODO Auto-generated method stub
Toast.makeText(getReactApplicationContext(), "算路失败", Toast.LENGTH_SHORT).show();
}
}
//添加的导航内容结束
// ReactContextBaseJavaModule要求派生类实现getName方法。这个函数用于返回一个字符串
// 这个字符串用于在JavaScript端标记这个原生模块
@Override
public String getName() {
return "ToastByAndroid";
}
// 获取应用包名
// 要导出一个方法给JavaScript使用,Java方法需要使用注解@ReactMethod
@ReactMethod
public void getPackageName() {
// String name = getReactApplicationContext().getPackageName();
// Toast.makeText(getReactApplicationContext(),name,Toast.LENGTH_LONG).show();
//调用实时导航的函数
routeplanToNavi(BNRoutePlanNode.CoordinateType.BD09LL);
}
}
注意:this.getCurrentActivity()
实现的思路是点击RN上的按钮先调用Android原生中的getPackageName方法,执行此方法时会执行开始导航的方法。
6、此时运行发现并没有跑通,经过多方面资讯,将项目引入的libgnustl_shared.so文件删除即可。
完!