如何把React Native嵌入到原生android应用中
2016-10-14 16:31
906 查看
原生应用不仅可以跳转到RN页面,也可以吧RN的组件放到原生应用中,作为原生应用的一部分。
首先介绍如何把react native嵌入到android中,然后再介绍如何把RN嵌入到ios中;
二、打开命令行终端,进入RnInAndroid,
2.1、输入以下命令:
npm init
然后会创建一个package.json的文件,搞过RN的我们知道,这是RN的配置文件,下面需要我们输入一些信息:
2.2、输入yes,创建好package.json文件,然后输入:
npm install--save
react react-native
会自动联网下载rn的组件库node_modules,
2.3、接着输入:
curl-o.flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
2.4、进入项目下面,打开刚才创建的package.json,在"scripts"--》
"test"的这一行后面添加个逗号,要不然报错的,这是json的格式,然后在test的下一行,添加一行代码:
"start":
"node node_modules/react-native/local-cli/cli.js start"
2.5、然后在项目目录下穿件一个index.android.js的文件,然后把下面的代码拷贝到文件中,下面的代码是RN的代码,现实的是一个页面,里面有一个Text的组件,相当于android中的textview:
'use
strict';
import
React from 'react';
import{
AppRegistry,
StyleSheet,
Text,
View}
from 'react-native';
classHelloWorld
extends React.Component{
render(){
return(
<View
style={styles.container}>
<Text
style={styles.hello}>这就是RN的页面哦</Text>
<Text
style={styles.hello}>我是刘成</Text>
</View>
)
}
}
var
styles =
StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
},
hello:{
fontSize:20,
textAlign:'center',
margin:10,
},
});
AppRegistry.registerComponent('HelloWorld',()=>
HelloWorld);
2.6、把你的项目下面的app(我的是
RnInAndroid/app)下的build.gradle文件打开,
在
dependencies 的代码块内,添加如下代码:
compile"com.facebook.react:react-native:+"
2.7、在项目根目录的build.gradle(我的是:RnInAndroid/build.gradle)中添加react
native 路径,这个文件和上面的那个build.gradle文件不一样哦:找到 allprojects代码块,找到repositories ,在这个代码块内添加如下的代码:
maven
{
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
如:
2.8、打开项目名/app/src/main/AndroidManifest.xml,在manifest标签内,和application同一级,添加联网权限:
<uses-permission
android:name="android.permission.INTERNET"/>
三、添加原生代码
3.1、在项目名/app/src/main/java/com/项目名.../rninandroid/,在这个目录下面创建一个java文件,文件名为:MyReactActivity.java,
然后复制下面的代码:
注意:
3.1.1、如果你用的是android studio的话,点击最上面的build菜单,clean project,然后会提示你有些包没有导入,按 alt + enter,一个一个的导入包;
3.1.2、上面代码的第一行:package是你自己的包名,在AndroidManifest.xml里面的package属性值里面有;
3.1.3、如果你的index.android.js的
AppRegistry.registerComponent('Liucheng', () => Liucheng),那就把上面代码中的"HelloWorld"改成“Liucheng”,我这里是Liucheng举个例子,
只要我们新建一个xml的布局文件,布局中添加一个linearlayout或者relativelayout布局,然后在代码中把这个RN的布局添加进去就行了,或者是在xml中直接添加RN布局代码:
下面就两种凡是贴出代码,供大家参考使用:
第一种种新建一个myreactactivity.xml布局文件:
在MyReactActivtiy.java中修改代码,红色部分为增加的内容:
第二种方法直接在布局中引用ReactRootView控件:
代码文件为:
六、今天到此为止吧,本来还想把IOS端的搞一下,明天再发一篇文章吧,各种坑各种坑!!!我在修路我在补坑,让你们踏着我们的肩膀跑的更高看的更远;
留个小问题:RN页面如何返回到原生页面上,如何处理android的物理返回按键,等我后天处理教大家哦!
首先介绍如何把react native嵌入到android中,然后再介绍如何把RN嵌入到ios中;
第一部分:将RN嵌入到android中的步骤如下
一、用Android Studio 创建一个程序,我的是RnInAndroid;二、打开命令行终端,进入RnInAndroid,
2.1、输入以下命令:
npm init
然后会创建一个package.json的文件,搞过RN的我们知道,这是RN的配置文件,下面需要我们输入一些信息:
2.2、输入yes,创建好package.json文件,然后输入:
npm install--save
react react-native
会自动联网下载rn的组件库node_modules,
2.3、接着输入:
curl-o.flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
2.4、进入项目下面,打开刚才创建的package.json,在"scripts"--》
"test"的这一行后面添加个逗号,要不然报错的,这是json的格式,然后在test的下一行,添加一行代码:
"start":
"node node_modules/react-native/local-cli/cli.js start"
2.5、然后在项目目录下穿件一个index.android.js的文件,然后把下面的代码拷贝到文件中,下面的代码是RN的代码,现实的是一个页面,里面有一个Text的组件,相当于android中的textview:
'use
strict';
import
React from 'react';
import{
AppRegistry,
StyleSheet,
Text,
View}
from 'react-native';
classHelloWorld
extends React.Component{
render(){
return(
<View
style={styles.container}>
<Text
style={styles.hello}>这就是RN的页面哦</Text>
<Text
style={styles.hello}>我是刘成</Text>
</View>
)
}
}
var
styles =
StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
},
hello:{
fontSize:20,
textAlign:'center',
margin:10,
},
});
AppRegistry.registerComponent('HelloWorld',()=>
HelloWorld);
2.6、把你的项目下面的app(我的是
RnInAndroid/app)下的build.gradle文件打开,
在
dependencies 的代码块内,添加如下代码:
compile"com.facebook.react:react-native:+"
2.7、在项目根目录的build.gradle(我的是:RnInAndroid/build.gradle)中添加react
native 路径,这个文件和上面的那个build.gradle文件不一样哦:找到 allprojects代码块,找到repositories ,在这个代码块内添加如下的代码:
maven
{
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
如:
2.8、打开项目名/app/src/main/AndroidManifest.xml,在manifest标签内,和application同一级,添加联网权限:
<uses-permission
android:name="android.permission.INTERNET"/>
三、添加原生代码
3.1、在项目名/app/src/main/java/com/项目名.../rninandroid/,在这个目录下面创建一个java文件,文件名为:MyReactActivity.java,
然后复制下面的代码:
package com.example.vittorio.rninandroid; import android.app.Activity; import android.os.Bundle; import com.facebook.react.LifecycleState; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactRootView; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.shell.MainReactPackage; /** * Created by vittorio on 2016/10/14. */ public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) //.setUseOldBridge(true) // uncomment this line if your app crashes .build(); mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null); setContentView(mReactRootView); } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } }
注意:
3.1.1、如果你用的是android studio的话,点击最上面的build菜单,clean project,然后会提示你有些包没有导入,按 alt + enter,一个一个的导入包;
3.1.2、上面代码的第一行:package是你自己的包名,在AndroidManifest.xml里面的package属性值里面有;
3.1.3、如果你的index.android.js的
AppRegistry.registerComponent('Liucheng', () => Liucheng),那就把上面代码中的"HelloWorld"改成“Liucheng”,我这里是Liucheng举个例子,
mReactRootView.startReactApplication(mReactInstanceManager, "Liucheng", null);点击
3.1.4、如果出现下面的错误:
Error:Conflict with dependency 'com.google.code.findbugs:jsr305'. Resolved versions for app (3.0.0) and test app (2.0.1) differ. See
http://g.co/androidstudio/app-test-app-conflict for details
解决办法:需要在你的根目录的build.gradle中的android代码快内,添加如下的代码:
configurations.all { resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0' }如下图所示:
3.1.5、重新编译:在android studio(简称:AS)中点击上边的build菜单,选择rebuild project;
3.2、在AndroidManifest.xml文件中,注册刚才新建的activity(MyReactActivity),并为它指定一个主题:
<activity android:name=".MyReactActivity" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> </activity>3.3、在 MyReactActivity.java文件中添加生命周期函数:
@Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onPause(); } } @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onResume(this, this); } } @Override protected void onDestroy() { super.onDestroy(); if (mReactInstanceManager != null) { mReactInstanceManager.onDestroy(); } } // We also need to pass back button events to React Native: @Override public void onBackPressed() { if (mReactInstanceManager != null) { mReactInstanceManager.onBackPressed(); } else { super.onBackPressed(); } }3.4、添加按键的响应,默认的意思是摇动设备出来菜单,但是在模拟器中不好使,所以我们需要添加相应的代码来处理物理按键,用as的模拟器按下ctrl+M会触发响应的按键:下面的代码也是在MyReactActivity.java文件中添加的哦:
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { mReactInstanceManager.showDevOptionsDialog(); return true; } return super.onKeyUp(keyCode, event); }3.5、在MainActivity.java的布局中(activity_main.xml中)添加一个按键,并在MAinActivity中添加这个按键的作用,作用是按下这个按键,就跳转到RN的界面,也就是跳转到MyReactActivtiy,具体代码如下:
3.6、现在命令行中启动nodejs服务器:
npm start
3.7、打开模拟器(我用的是Genymotion,你也可以用as自带的模拟器或者真机测试),然后在AS运行点击Run:
四、坑爹了,原生的代码能正常显示,但是点击跳转RN的界面,就退出了,
4.1、报错如下:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.vittorio.rninandroid, PID: 13885 android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@d6bfdbd -- permission denied for window type 2003 at android.view.ViewRootImpl.setView(ViewRootImpl.java:702) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) at android.app.Dialog.show(Dialog.java:316) at com.facebook.react.devsupport.DevSupportManagerImpl.handleReloadJS(DevSupportManagerImpl.java:538) at com.facebook.react.ReactInstanceManagerImpl$3$1.run(ReactInstanceManagerImpl.java:386) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6077) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
解决办法:增加权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />4.2、但是依旧报错,在activit的点击事件里面添加:[/code]
4.3、依旧报错:
java.lang.IllegalAccessError: Method 'void android.support.v4.net.ConnectivityManagerCompat.()' is inaccessible to class 'com.f
acebook.react.modules.netinfo.NetInfoModule' (declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' appears in
/data/app/package.name-2/base.apk)
解决办法:(老外也遇到了这样的问题https://github.com/facebook/react-native/issues/6152#issuecomment-200759453)
在项目下修改以下的文件内容:
.gitignore(在该文件里添加排除项,node_modules/ 和 npm-debug.log) app/build.gradle (将 'com.android.support:appcompat-v7:24.2.1' 改为 'com.android.support:appcompat-v7:23.0.1') gradle.properties (在文件末尾添加,android.useDeprecatedNdk=true)
4.4、编译依旧报错:
undefined is not a function (evaluating 'remoteModules.forEach')
解决办法:
在项目下面的build.gradle为把
maven { // All of React Native (JS, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" }修改成:[/code]
maven { // All of React Native (JS, Android binaries) is installed from npm url "$rootDir/node_modules/react-native/android" },因为$rootDir就是你的项目目录,如果用../的话,找不到这个目录就会报错的[/code]
4.5.依旧报错啊,报错啊:
Error:(52, 34) 错误: 找不到符号 符号: 方法 onPause() 位置: 类型为ReactInstanceManager的变量 mReactInstanceManager Error:(61, 34) 错误: 找不到符号 符号: 方法 onResume(MyReactActivity,MyReactActivity) 位置: 类型为ReactInstanceManager的变量 mReactInstanceManager Error:(70, 34) 错误: 找不到符号 符号: 方法 onDestroy() 位置: 类型为ReactInstanceManager的变量 mReactInstanceManager
解决原因:找了好长时间的答案,也没有找到原因在哪儿,只能先把onpause、onResume、onDestroy这三个方法注释掉,
编译成功啦!!!真高兴啊真高兴;
4.6、但是进入RN的页面后按下Ctrl+M,没反应,不能调出调试菜单:
在AndroidMenifest.xml文件中添加:[code]<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
就可以了
五、将RN作为组件嵌入到android中作为一个控件使用:
5.1、我们注意到在MyReactActivtiy.java文件中,我们发现其实这个activity加载页面也用的是[code]setContentView(mReactRootView);
只要我们新建一个xml的布局文件,布局中添加一个linearlayout或者relativelayout布局,然后在代码中把这个RN的布局添加进去就行了,或者是在xml中直接添加RN布局代码:
下面就两种凡是贴出代码,供大家参考使用:
第一种种新建一个myreactactivity.xml布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="200dp" android:text="上半部分是android的布局" android:background="#6638" android:textSize="30sp" android:gravity="center"/> <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="wrap_content"></LinearLayout> </LinearLayout>
在MyReactActivtiy.java中修改代码,红色部分为增加的内容:
package com.example.vittorio.rninandroid; import android.app.Activity; import android.os.Bundle; import android.view.KeyEvent; import android.widget.LinearLayout; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactRootView; import com.facebook.react.common.LifecycleState; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.shell.MainReactPackage; /** * Created by liucheng on 2016/10/14. */ public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; private LinearLayout ll; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) //.setUseOldBridge(true) // uncomment this line if your app crashes .build(); mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null); setContentView(R.layout.myreactactivity); initView(); } 。。。 private void initView() { ll = (LinearLayout) findViewById(R.id.ll); ll.addView(mReactRootView); } }
第二种方法直接在布局中引用ReactRootView控件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="200dp" android:text="上半部分是android的布局" android:background="#6638" android:textSize="30sp" android:gravity="center"/> <!--<LinearLayout--> <!--android:id="@+id/ll"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="wrap_content"></LinearLayout>--> <com.facebook.react.ReactRootView android:id="@+id/rnview" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
代码文件为:
public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; // private LinearLayout ll; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.myreactactivity); // mReactRootView = new ReactRootView(this);注释掉这一行,不新建一个RN的view了,因为我们已经引用了,不需要重新创建了 mReactRootView = (ReactRootView)findViewById(R.id.rnview); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) //.setUseOldBridge(true) // uncomment this line if your app crashes .build(); mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null); // initView(); } ... //记得把上面新建的的initView()方法给删除其他的和上面类似 }
六、今天到此为止吧,本来还想把IOS端的搞一下,明天再发一篇文章吧,各种坑各种坑!!!我在修路我在补坑,让你们踏着我们的肩膀跑的更高看的更远;
留个小问题:RN页面如何返回到原生页面上,如何处理android的物理返回按键,等我后天处理教大家哦!
相关文章推荐
- Android 原生应用嵌入React-Native模块开发-环境配置及填坑记
- 在Android原生应用中嵌入ReactNative页面
- react native 学习笔记----将react native嵌入到Android原生应用
- React Native嵌入Android原生项目中
- React Native嵌入原生应用的坑
- React-native植入原生Android应用
- 在Android原生中嵌入React Native,进而React Native调用原生
- ReactNative跟Android原生模块是如何进行数据交互实例
- Android React Native植入原生应用小记
- Android原生应用集成ReactNative坑总结
- 如何创建一个Android原生的react-native组件(一)
- Android原生嵌入React Native详解
- android 原生app嵌入reactnative页面
- React-Native学习之嵌入Android原生项目
- 2.android 原生应用和React native 结合开发.环境搭建
- React Native植入原生Android应用的流程解析
- 将React Native集成至Android原生应用
- react-native + as <react-native嵌入原生应用开发>
- React Native嵌入Android原生项目中(两种方法)
- React Native Android原生模块开发实战|教程|心得|如何创建React Native Android原生模块