原生代码中接入React Native

查阅网上资源和博客,全部是在原生的基础上一点一点的加文件实现使原生项目变成React Native项目,步骤较多,比较复杂,容易出现各种问题,对于项目不是很大,文件目录不是过于复杂的原生项目尝试利用先新建React Native项目,然后将原生代码集成进去的办法(基于Android平台、IOS类似)。


一、打开现有项目

利用Android Studio打开现有原生项目,如下图所示。



二、初始化一个React Native项目

这里不再赘述,现在书籍或者网上相关文档很多,跑一遍测试能否正常运行。


三、更换包名及appid

如果新建完成后的React Native项目中android目录中的包名和appid不一致,可以将包名和appid修改,然后重新跑一遍工程检测是否能够运行。这样为了做到和之前原生代码一致,如果没有此方面需求或者新建完成后的项目包名和appid都一样则可以跳过此步骤。


四、将原生项目中指定目录copy到React Native项目中

主要涉及java目录、res目录、assets目录、jniLibs与lib目录、build.gradle与AndroidManifest配置文件,如下图所示,左侧为原生工程目录,右侧为React Native中的android目录。



最关键并且需要注意的是build.gradle与AndroidManifest两个配置文件,build.gradle文件中的依赖只移动红色区域部分依赖,蓝色部分为React Native项目初始化化时自动生成的,不用动,如下图所示。




AndroidManifest配置文件中需要移动<uses-permission android:name="android.permission.INTERNET" />类似各种权限的部分和注册的Activity部分,如果lib下的jar包不能识别,需要右键jar然后add as library。 复制完毕以上目录和文件再用Android Studio跑一遍,测试程序能否跑通。


五、编写代码

(1) 参见React Native与原生混编博客,可以实现从React Native到原生或者原生到React Native页面,这里不再赘述。


(2) React Native中MainApplication与之前原生代码中XXXApplication的代码合并,这个是要注意的地方,没有冲突的情况下,建议直接将XXXApplication的代码粘贴到ReactNative自动生成的MainApplication中,如果有代码冲突,具体问题具体分析。


(3) 在原生代码MainActivity的恰当位置或者想用React Native去实现的页面编写跳转React Native的代码逻辑。

Intent intent = new Intent(MainActivity.this,ReactNativeActivity.class); 
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
startActivity(intent);

(4) 在ReactNativeActivity中去实现DefaultHardwareBackBtnHandler类,并且去覆写指定方法。onCreate方法中编写加载bundle文件代码及赋值一些设置信息。完整代码如下图所示。

public class ReactNativeActivity  extends Activity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
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)
                .build();
mReactRootView.startReactApplication(mReactInstanceManager,"ReactNativeProjectName",null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackpressed() {
super.onBackpressed();
}
@Override
protected void onPause() {
super.onPause();
        if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause();
}
    }
@Override
protected void onResume() {
super.onResume()
        if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this,this);
}
    }

@Override
protected void onDestroy() {
super.onDestroy();

        if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy();
}
    }

@Override
public void onBackpressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackpressed();
} else {
super.onBackpressed();
}
    }

@Override
public boolean onKeyUp(int keyCode,KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU &&mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
            return true;
}
return super.onKeyUp(keyCode,event);
}


}

注意setBundleAssetName中index.android.bundle的全称,这需要和android工程目录下assets一致;setJSMainModuleName中index.android要与React Native侧的首个启动js页名称一致;startReactApplication中的第二个参数要与React Native侧的注册组件名称一致。


(5) 原生代码唤起React Native侧代码程序入口完全在(4)中完成,这时建立新工程时自动生成的MainActivity如下图所示完全没有用了,可以考虑删除掉。


(6) 终端到项目根目录下,执行react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/。目的是在android的工程目录下assets中生成index.android.bundle文件和index.android.bundle.Meta文件。也就是说所有编写的React Native代码会打包进index.android.bundle文件中,供原生代码调用


(7) 利用Android Studio运行该程序,点击,即可完成从原生到React Native页面跳转,原生代码中成功嵌入了React Native的代码


六、遇到的问题及解决办法

(1) 终端出现如下日志,bundle文件才算正式生成成功。



(2) 修改package.json文件和终端执行生成bundle文件命令,二选一,不要二者都操作一遍。(本例是采用终端键入react-native bundle --platform android--dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/的方式)


(3) ReactNative页面是基于原生的,原生调用的是assets目录下打包好的bundle文件,所以利用命令打包之前js文件最好是准确无误可以跑通的,因为js每调试一次就得利用命令生成一次,目前在网上还没有查到更好的方式(欢迎留言指导)。目前尝试出的一个比较好的方式是:在注册文件AndroidManifest中设置启动页为React Native自动生成的MainActivity,这样启动时就能调试js代码

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...