React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)

本文深入探讨React Native Android应用的启动流程,重点解析ReactRootView、ReactInstanceManager和JSBundleLoader的角色。通过源码分析,揭示Java与JS之间的通信机制,包括模块注册、创建ReactContext、调用JS端代码的过程,以及热更新的核心思路。
摘要由CSDN通过智能技术生成

}

可以看见,ReactRootView 果然是个牛逼的类,我也不多解释了,大段的英文注释已经交代很清楚用途和地位了,我们直接看上面代码的 startReactApplication 方法吧,可以看见他又调用了一个三个参数的同名方法,具体这三个参数来历如下(也是我们自己集成 RN 时手动 builder 模式创建的):

1. reactInstanceManager: 大内总管接口类,提供一个构造者模式的初始化 Builder,实现类是 XReactInstanceManagerImpl,这类也是我们在集成 RN 时 new ReactRootView 的之前自己创建的。

2. moduleName: 与 JS 代码约定的 String 类型识别 name,JS 端通过 AppRegistry.registerComponent 方法设置这个 name,Java 端重写基类的 getMainComponentName 方法设置这个 name,这样两边入口就对上了。

3. launchOptions: 这里默认是 null 的,如果自己不继承 ReactActivity 而自己实现的话可以通过这个参数在 startActivity 时传入一些参数到 JS 代码,用来依据参数初始化 JS 端代码。

这些参数都初始化传递好了以后,可以看见接着调用了 mReactInstanceManager 的 createReactContextInBackground 方法,mReactInstanceManager 就是上面说的第一个参数,实质是通过一个构造者模式创建的,实现类是 XReactInstanceManagerImpl,所以我们直接跳到 XReactInstanceManagerImpl 的 createReactContextInBackground 方法看看,如下:

public void createReactContextInBackground() {

recreateReactContextInBackgroundInner();

}

private void recreateReactContextInBackgroundInner() {

UiThreadUtil.assertOnUiThread();

if (mUseDeveloperSupport && mJSMainModuleName != null) {

//如果是 dev 模式,BuildConfig.DEBUG=true就走这里,在线更新bundle,手机晃动出现调试菜单等等。

//这个路线属于RN调试流程原理,后面再写文章分析,这里我们抓住主线分析

return;

}

//非调试模式,即BuildConfig.DEBUG=false时执行

recreateReactContextInBackgroundFromBundleLoader();

}

private void recreateReactContextInBackgroundFromBundleLoader() {

//厉害了,word哥,在后台创建ReactContext,两个参数是重点。

//mJSCConfig.getConfigMap()默认是一个WritableNativeMap,在前面通过构造模式构造时通过Builder类的set方法设置。

//mJSBundleLoader是在前面通过构造模式构造时通过Builder类的多个setXXX方法均可设置的,

//最终在Builder中build方法进行判断处理,你可以自定义Loader,或者按照build方法规则即可,

//默认是JSBundleLoader.createAssetLoader静态方法返回的JSBundleLoader抽象类的实现类。

//自定义热更新时setJSBundleFile方法参数就是巧妙的利用这里是走JSBundleLoader.createAssetLoader还是JSBundleLoader.createFileLoader!!!!!!

recreateReactContextInBackground(

new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),

mBundleLoader);

}

private void recreateReactContextInBackground(

JavaScriptExecutor.Factory jsExecutorFactory,

JSBundleLoader jsBundleLoader) {

UiThreadUtil.assertOnUiThread();

//封装一把,把两个参数封装成ReactContextInitParams对象

ReactContextInitParams initParams =

new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);

if (mReactContextInitAsyncTask == null) {

//初始化进来一定会走啦,这货不就是创建一个AsyncTask,然后执行,同时传递封装的参数initParams给task。

// No background task to create react context is currently running, create and execute one.

mReactContextInitAsyncTask = new ReactContextInitAsyncTask();

mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams);

} else {

// Background task is currently running, queue up most recent init params to recreate context

// once task completes.

mPendingReactContextInitParams = initParams;

}

}

通过上面注释可以看见,我们《React Native Android 从学车到补胎和成功发车经历 #3-5 RN 集成后热更新核心思路》的热更新面纱也是从这个地方开始揭晓的,ReactInstanceManager 的 setJSBundleFile 如下:

/**

  • Path to the JS bundle file to be loaded from the file system.

  • Example: {@code “assets://index.android.js” or “/sdcard/main.jsbundle”}

*/

public Builder setJSBundleFile(String jsBundleFile) {

if (jsBundleFile.startsWith(“assets://”)) {

mJSBundleAssetUrl = jsBundleFile;

mJSBundleLoader = null;

return this;

}

return setJSBundleLoader(JSBundleLoader.createFileLoader(jsBundleFile));

}

我们先记住这个提示,后面再边分析主加载流程边插入介绍热更新的原理,所以我们还是把思路先回到 XReactInstanceManagerImpl 内部类的 ReactContextInitAsyncTask 上,如下:

private final class ReactContextInitAsyncTask extends

AsyncTask<ReactContextInitParams, Void, Result> {

@Override

protected Result doInBackground(ReactContextInitParams… params) {

try {

//异步执行的重量级核心方法createReactContext,创建ReactContext

JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();

return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));

} catch (Exception e) {

// Pass exception to onPostExecute() so it can be handled on the main thread

return Result.of(e);

}

}

@Override

protected void onPostExecute(Result result) {

try {

//回到主线程执行的重量级核心方法setupReactContext,设置ReactContext相关

setupReactContext(result.get());

} catch (Exception e) {

mDevSupportManager.handleException(e);

} finally {

mReactContextInitAsyncTask = null;

}

}

}

可以看见,这就是典型的 AsyncTask 用法,我们先关注 doInBackground 方法,onPostExecute 方法等会回头再看;doInBackground 中首先把上面封装的 ReactContextInitParams 对象里 JavaScriptExecutor.Factory 工厂对象拿到,接着调用了工厂类的 create 方法创建 JavaScriptExecutor 抽象类的实现类 JSCJavaScriptExecutor 对象(因为上面分析 recreateReactContextInBackground 方法时第一个参数传入的是 new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()))。接着往下执行了 createReactContext 方法,两个参数分别是前面封装的 ReactContextInitParams 对象中的 JSCJavaScriptExecutor 实例和 JSBundleLoader.createAssetLoader 静态方法创建的匿名内部类 JSBundleLoader 对象(热更新的话可能是另一个 Loader,参见前面分析);createReactContext 方法如下(有点长,但是句句核心啊):

private ReactApplicationContext createReactContext(

JavaScriptExecutor jsExecutor,

JSBundleLoader jsBundleLoader) {

//这货默认不就是上面刚刚分析的"assets://" + bundleAssetName么

mSourceUrl = jsBundleLoader.getSourceUrl();

List moduleSpecs = new ArrayList<>();

Map<Class, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();

//!!!Js层模块注册表,通过它把所有的JavaScriptModule注册到CatalystInstance。我们自定义的继承JavaScriptModule接口的Java端也是通过他来管理。

JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();

//ContextWrapper封装类,其实就是getApplicationContext的封装,用在ReactContext中

final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

//如果是开发模式下ReactApplicationContext中有崩溃就捕获后交给mDevSupportManager处理(出错时弹个红框啥玩意的都是这货捕获的功劳)

if (mUseDeveloperSupport) {

//mDevSupportManager实例对象来源于XReactInstanceManagerImpl构造方法中一个工厂方法,实质由useDeveloperSupport决定DevSupportManager是哪个实例。

//非开发模式情况下mDevSupportManager为DisabledDev

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值