从Android的角度窥探ReactNative的原理

2,003 阅读17分钟

1 简介

1.1 ReactNative的跨平台

ReactNative是一种跨平台开发App的技术,跨平台使得用一套代码就能在多个平台发布,节省了人力和各种资源。

怎么实现跨平台呢?回想两个我们已经掌握的知识你就能明白了。

1 回想一下当我们遇到大量重复性代码的时候会怎么做?是不是会考虑将有共性的东西抽象出来,同一个App虽然在Android和IOS的两个平台上代码实现上完全不同,但其实视图、交互以及业务逻辑这些都是具有共性的,是可以抽象出来的。

2 java也是跨平台的,我们回想一下java一次编译,到处运行的原理:先将java编译成字节码,然后在不同平台,jvm使用其内部相应的解释器解释成机器码(每个平台解释出来的机器码内容是不同的,看完下一段话后自己思考一下对应了什么!)。

因此我们可以这样实现跨平台:将视图、交互以及业务逻辑抽象出来,然后使用同一套代码(RN选择了Js)来实现,最后再使用不同的解释器,解释给各个平台。

1.2 简析RN工程的架构

本质上RN是一个第三方框架,它提供了执行js代码的能力,同时搭建了一套js和原生(Android和IOS)的通信体系。原生使用这个框架后,就可以将一部分功能的实现和逻辑的处理转移到js(本来实现这部分的功能和逻辑需要两套代码,即Android和IOS各自实现一遍,现在使用js一套代码就能实现)。由此可见尽可能的将更多的功能用js来实现就能节省更多的代码,但实际上js能力是十分有限的,比如js没有绘制引擎,因此我们用js写的UI本质上,最终是js告知原生UI的信息(位置,大小,颜色等),由原生负责真正的绘制。

可以看出js更多的是一种逻辑处理,而原生负责真正的实现,核型工作原理就是js和原生通过RN搭建的通讯体系进行协作和通讯。

具体native和js是怎么协作和通讯的呢?从使用的角度,我们只需要知道,js如何调用native和native如何调用js。要深入探究原理的话,由于两者的底层通讯是用c++实现的,就变成了js调用c++,c++调用原生,以及原生调用c++,c++调用js。由于我暂时不会c++,接下来的分析涉及到的RN源码只限于java和js。

2 RN的启动流程

RN项目是原生项目的扩展(我们的js代码被打包成一个bundle文件,作为资源文件放在原生项目中),本质上还是原生项目。因此我们从Android项目的角度入手,结合源码进行分析。

2.1 创建Application

Android项目启动的第一步当然是创建Application对象,来看看RN为我们提供的ReactApplication。

public interface ReactApplication {
  ReactNativeHost getReactNativeHost();
}

ReactApplication是一个接口,提供一个返回ReactNativeHost对象的方法。

再来看看RN项目默认创建的Application。

public class MainApplication extends Application implements ReactApplication { // 实现ReactApplication接口
  private final ReactNativeHost mReactNativeHost = 
      new ReactNativeHost(this) {// 创建一个final的ReactNativeHost对象
        @Override
    		// 配置是否是dev(开发)模式,是的话会开启一些调试,同时导致加载jsBundle的方式不一样。
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() { // 配置要加载的ReactPackage
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() { // 配置js的入口模块名
          return "index";
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {// 提供一个返回ReactNativeHost对象的方法
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    // SoLoader是so文件加载库,用来加载C/C++底层库
    SoLoader.init(this, /* native exopackage */ false);
    // 初始化Flipper。Flipper是facebook推出的用于 debug ios、Android、React Native 应用的工具。
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

  /**
   * Loads Flipper in React Native templates. Call this in the onCreate method with something like
   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
   *
   * @param context
   * @param reactInstanceManager
   */
  private static void initializeFlipper(
      Context context, ReactInstanceManager reactInstanceManager) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.awesomeproject.ReactNativeFlipper");
        aClass
            .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
            .invoke(null, context, reactInstanceManager);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }
}

类似我们平时提供一个全局的ApplicaitionContext一样,这里提供了一个全局的ReactNativeHost对象。ReactNativeHost是一个抽象类,我们可以通过重写它的方法(getUseDeveloperSupport和getPackages没有默认实现,必须重写)来实现一些关于RN的全局配置。一个ReactPackage可以配置多个ViewManager、NativeModule,这部分是关于js调用原生的使用,详见ReactNative官方文档。

2.2 创建Activity

下一步就是创建MainActivity了,来看看RN项目默认创建的MainActivity。

public class MainActivity extends ReactActivity {

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  @Override
  protected String getMainComponentName() {// 返回js注册的主组件名。后续存到ReactRootView的mJSModuleName属性。
    return "AwesomeProject";
  }
}

继承了ReactActivity,重写了getMainComponentName方法。

Activity创建完就该走生命周期流程了,我们的onCreate方法呢?让我们进入ReactActivity一起看看。

2.2.1 ReactActivity

public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {

  private final ReactActivityDelegate mDelegate;

  // 初始化时创建ReactActivityDelegate代理对象
  protected ReactActivity() { 
    mDelegate = createReactActivityDelegate();
  }

  protected @Nullable String getMainComponentName() {
    return null;
  }

  // 创建ReactActivityDelegate时,为其绑定当前Activity和mainComponentName。
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName());
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }

  ...
  // 其他委派方法
}

ReactActivity初始化时创建ReactActivityDelegate代理对象,并将自己的生命周期、硬件返回按钮事件和权限相关的回调,全部委派给了ReactActivityDelegate对象。因此ReactActivity的onCreate方法就进入到了ReactActivityDelegate的onCreate方法。

2.2.2 ReactActivityDelegate

public class ReactActivityDelegate {

  private final @Nullable Activity mActivity;
  private final @Nullable String mMainComponentName;

  private @Nullable PermissionListener mPermissionListener;
  private @Nullable Callback mPermissionsCallback;
  private ReactDelegate mReactDelegate;

  @Deprecated
  public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
    mActivity = activity;
    mMainComponentName = mainComponentName;
  }

  // 初始化绑定了宿主ReactActivity和js主组件名
  public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
    mActivity = activity;
    mMainComponentName = mainComponentName;
  }

  protected @Nullable Bundle getLaunchOptions() {
    return null;
  }

  protected ReactRootView createRootView() {// 默认创建ReactRootView的方法,可以重写此方法来自定义创建方法。
    return new ReactRootView(getContext());
  }

  protected ReactNativeHost getReactNativeHost() {
    return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
  }

  public ReactInstanceManager getReactInstanceManager() {
    return mReactDelegate.getReactInstanceManager();
  }

  public String getMainComponentName() {
    return mMainComponentName;
  }

  protected void onCreate(Bundle savedInstanceState) {
    String mainComponentName = getMainComponentName();
    // 创建ReactDelegate对象
    mReactDelegate =  
        new ReactDelegate(
            getPlainActivity(), // 宿主Activity
      			getReactNativeHost(), // 全局的ReactNativeHost对象
      			mainComponentName, // js入口组件
      			getLaunchOptions()) // Bundle对象,用来存放传递给js的初始化参数,默认为null
    		{
          @Override
          protected ReactRootView createRootView() { // 配置初始化ReactRootView的方法,
            return ReactActivityDelegate.this.createRootView();
          }
        };
    // 之前配置的mainComponentName不为空的话调用loadApp方法
    if (mMainComponentName != null) {
      loadApp(mainComponentName);// 传入mainComponentName
    }
  }

  protected void loadApp(String appKey) {
    // 加载js代码的入口
    mReactDelegate.loadApp(appKey);
    // 为宿主Activity绑定contentView(熟悉吗OvO)
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  }
  ...

  protected Context getContext() {
    return Assertions.assertNotNull(mActivity);
  }

  protected Activity getPlainActivity() {
    return ((Activity) getContext());
  }
}

在onCreate方法中首先创建ReactDelegate对象,然后调用了ReactDelegate的loadApp方法,最后在调用setContentView方法传入了一个ReactRootView。**本质上比起普通的Activity,只是setContentView的内容不一样了。**前面说过js负责告诉原生视图长啥样,原生负责渲染,ReactRootView就是js给原生的答案,让我们看看ReactDelegate的loadApp方法。

2.2.3 ReactDelegate

public class ReactDelegate {

  private final Activity mActivity;
  private ReactRootView mReactRootView;

  @Nullable private final String mMainComponentName;

  @Nullable private Bundle mLaunchOptions;

  @Nullable private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;

  private ReactNativeHost mReactNativeHost;

  public ReactDelegate(
      Activity activity,
      ReactNativeHost reactNativeHost,
      @Nullable String appKey,
      @Nullable Bundle launchOptions) {
    mActivity = activity;
    mMainComponentName = appKey;
    mLaunchOptions = launchOptions;
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
    mReactNativeHost = reactNativeHost;
  }
  ...

  public void loadApp() {
    loadApp(mMainComponentName);
  }

  public void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    mReactRootView = createRootView();// 创建一个ReactRootView对象
    mReactRootView.startReactApplication( // 然后调用startReactApplication方法
        getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
  }

  public ReactRootView getReactRootView() {
    return mReactRootView;
  }

  // ReactActivityDelegate创建ReactDelegate时重写了此方法
  protected ReactRootView createRootView() {
    return new ReactRootView(mActivity);
  }

  ...

  private ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  public ReactInstanceManager getReactInstanceManager() {
    return getReactNativeHost().getReactInstanceManager();
  }
}

loadApp方法中首先创建一个ReactRootView对象,然后调用了ReactRootView对象的startReactApplication方法。

2.2.4 ReactRootView

ReactRootView的创建非常简单,我们的重点是startReactApplication方法:

public class ReactRootView extends FrameLayout implements RootView, ReactRoot {

  ...

  public ReactRootView(Context context) {
    super(context);
    init();
  }

  public ReactRootView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }

  public ReactRootView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }

  private void init() {
    setClipChildren(false);
  }
}

ReactRootView#startReactApplication:

mReactRootView.startReactApplication( 
	getReactNativeHost().getReactInstanceManager(), // 获取ReactInstanceManager对象
	appKey, // mainComponentName
	mLaunchOptions // 前面有提到,Bundle对象,存放传递给主组件的参数,默认为null
);

首先是调用ReactNativeHost对象的getReactInstanceManager()获取ReactInstanceManager对象。

2.2.5 ReactInstanceManager

ReactNativeHost.java

public abstract class ReactNativeHost {

  private final Application mApplication;
  // 全局唯一的ReactNativeHost管理了一个mReactInstanceManager对象,因此mReactInstanceManager也是全局单例。
  private @Nullable ReactInstanceManager mReactInstanceManager;

  protected ReactNativeHost(Application application) {
    mApplication = application;
  }

  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) { // 没有的话创建
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
      // 调用createReactInstanceManager方法创建一个ReactInstanceManager对象
      mReactInstanceManager = createReactInstanceManager();
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
    }
    return mReactInstanceManager;// 有的话直接返回
  }

  // 创建ReactInstanceManager对象的方法
  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    ReactInstanceManagerBuilder builder =
        ReactInstanceManager.builder()
            .setApplication(mApplication)// 应用上下文
            .setJSMainModulePath(getJSMainModuleName())// debug模式下jsBundle名
            .setUseDeveloperSupport(getUseDeveloperSupport())// 是否开启dev模式
            .setDevSupportManagerFactory(getDevSupportManagerFactory())
            .setRequireActivity(getShouldRequireActivity())
            .setSurfaceDelegateFactory(getSurfaceDelegateFactory())
            .setRedBoxHandler(getRedBoxHandler())
            .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
            .setUIImplementationProvider(getUIImplementationProvider())
            .setJSIModulesPackage(getJSIModulePackage())
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
            .setReactPackageTurboModuleManagerDelegateBuilder(
                getReactPackageTurboModuleManagerDelegateBuilder());

    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }

    // 配置jsBundle的加载路径(后续加载的时候用到)
    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    
    // 真正创建ReactInstanceManager的入口
    ReactInstanceManager reactInstanceManager = builder.build();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return reactInstanceManager;
  }

  // dev模式下从服务器传过来的jsBundle的默认名
  protected String getJSMainModuleName() {
    return "index.android";
  }

  // 通过配置jsBundle在资源文件夹(assets文件夹)下的文件名来加载jsBundle
  protected @Nullable String getBundleAssetName() {
    return "index.android.bundle";
  }
  
  // 通过配置jsBundle的文件路径来加载jsBundle,默认为null
  protected @Nullable String getJSBundleFile() {
    return null;
  }

  public abstract boolean getUseDeveloperSupport(

  protected abstract List<ReactPackage> getPackages();
    
  ...
  // 其他默认配置,大部分都是null
}

ReactNativeHost将核心任务统统交给了ReactInstanceManager,初始化ReactInstanceManager时,也初始化了很多关于RN的默认配置,包括是否开启debug模式,后续加载jsBundle的方式,ReactPackage等等,我们可以重写初始化ReactNativeHost的方法来修改默认配置。当然真正的创建在ReactInstanceManagerBuilder的build方法中。

ReactInstanceManagerBuilder.java#build

	public ReactInstanceManager build() {
    //一些断言
    ...

    if (mUIImplementationProvider == null) {
      // create default UIImplementationProvider if the provided one is null.
      mUIImplementationProvider = new UIImplementationProvider();
    }

    // We use the name of the device and the app for debugging & metrics
    //noinspection ConstantConditions
    String appName = mApplication.getPackageName();
    String deviceName = getFriendlyDeviceName();

    return new ReactInstanceManager(
        mApplication,
        mCurrentActivity,
        mDefaultHardwareBackBtnHandler,
        mJavaScriptExecutorFactory == null
            ? getDefaultJSExecutorFactory(appName, deviceName, mApplication.getApplicationContext())
            : mJavaScriptExecutorFactory,
        //创建JSBundleLoader对象来存储关于加载jsBundle的方式和路径,其内部后续再来看
        (mJSBundleLoader == null && mJSBundleAssetUrl != null)
            ? JSBundleLoader.createAssetLoader(
                mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
            : mJSBundleLoader,
        mJSMainModulePath,
        mPackages,
        mUseDeveloperSupport,
        mDevSupportManagerFactory == null
            ? new DefaultDevSupportManagerFactory()
            : mDevSupportManagerFactory,
        mRequireActivity,
        mBridgeIdleDebugListener,
        Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
        mUIImplementationProvider,
        mNativeModuleCallExceptionHandler,
        mRedBoxHandler,
        mLazyViewManagersEnabled,
        mDevBundleDownloadListener,
        mMinNumShakes,
        mMinTimeLeftInFrameForNonBatchedOperationMs,
        mJSIModulesPackage,
        mCustomPackagerCommandHandlers,
        mTMMDelegateBuilder,
        mSurfaceDelegateFactory
    );
  }

ReactInstanceManager中的一些配置,在后续使用到了再来分析,我们接着看startApplication方法。

ReactRootView.java#startApplication

  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties) {
    startReactApplication(reactInstanceManager, moduleName, initialProperties, null);
  }

  @ThreadConfined(UI)
  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties,
      @Nullable String initialUITemplate) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
    try {
      UiThreadUtil.assertOnUiThread();

      //断言,确保mReactInstanceManager不为空
      Assertions.assertCondition(
          mReactInstanceManager == null,
          "This root view has already been attached to a catalyst instance manager");

      mReactInstanceManager = reactInstanceManager;
      
      // 前面一路传进来的参数改个名而已
      // js主组件名,ReactActivity的getJSMainModuleName,ReactActivityDelegate的mainComponentName。
      mJSModuleName = moduleName;
      // 传递给js主组件的初始化数据,默认为null,ReactActivityDelegate的mLaunchOptions
      mAppProperties = initialProperties;
      mInitialUITemplate = initialUITemplate;

      // 创建ReactContext
      mReactInstanceManager.createReactContextInBackground();

    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

核心是调用了mReactInstanceManager的createReactContextInBackground()方法来创建ReactContext,ReactContext和其他Context一样继承ContextWrapper,是ReactNative的上下文,我们通过ReactContext来访问RN的各种核心实现类。

2.3 创建ReactContext

ReactInstanceManager.java#createReactContextInBackground

	@ThreadConfined(UI)
  public void createReactContextInBackground() {
    FLog.d(TAG, "ReactInstanceManager.createReactContextInBackground()");
    UiThreadUtil.assertOnUiThread(); 
    if (!mHasStartedCreatingInitialContext) {
      mHasStartedCreatingInitialContext = true;
      // 如果没有创建过ReactContext,就调用recreateReactContextInBackgroundInner方法创建
      recreateReactContextInBackgroundInner();
    }
  }

  //重新创建react的application和context,此方法用于配置发生变化或者我们主动要求重启RN应用时。
  @ThreadConfined(UI)
  public void recreateReactContextInBackground() {
    Assertions.assertCondition(
        mHasStartedCreatingInitialContext,
        "recreateReactContextInBackground should only be called after the initial "
            + "createReactContextInBackground call.");
    recreateReactContextInBackgroundInner();
  }

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundInner() {
    FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
    UiThreadUtil.assertOnUiThread();

    // 如果是dev环境且mJSMainModulePath不为空,则从metro服务器加载jsBundle
    if (mUseDeveloperSupport && mJSMainModulePath != null) {
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();

      if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
        if (mBundleLoader == null) {
          // 从metro服务器加载jsBundle
          mDevSupportManager.handleReloadJS();
        } else {
          mDevSupportManager.isPackagerRunning(
              new PackagerStatusCallback() {
                @Override
                public void onPackagerStatusFetched(final boolean packagerIsRunning) {
                  UiThreadUtil.runOnUiThread(
                      new Runnable() {
                        @Override
                        public void run() {
                          if (packagerIsRunning) {
                            mDevSupportManager.handleReloadJS();
                          } else if (mDevSupportManager.hasUpToDateJSBundleInCache()
                              && !devSettings.isRemoteJSDebugEnabled()
                              && !mUseFallbackBundle) {
                            // 在禁用远程JS调试的情况下,使用服务器之前下载的最新的jsBundle
                            onJSBundleLoadedFromServer();
                          } else {
                            // 如果dev服务器关闭了,则关闭远程JS调试。
                            devSettings.setRemoteJSDebugEnabled(false);
                            recreateReactContextInBackgroundFromBundleLoader();
                          }
                        }
                      });
                }
              });
        }
        return;
      }
    }
		// 非dev模式下调用
    recreateReactContextInBackgroundFromBundleLoader();
  }

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader");
    // mJavaScriptExecutorFactory默认为空,mBundleLoader保存了加载jsBundle的方式和路径,是前面创建ReactInstanceManager时,根据我们的配置创建的。
    recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
  }

	@ThreadConfined(UI)
  private void recreateReactContextInBackground(
      JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
    FLog.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackground()");
    UiThreadUtil.assertOnUiThread();

    final ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    if (mCreateReactContextThread == null) {
      // 如果当前没有创建ReactContext的线程,则创建一个新线程来创建ReactCotext。
      runCreateReactContextOnNewThread(initParams);
    } else {
      mPendingReactContextInitParams = initParams;
    }
  }

	@ThreadConfined(UI)
  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
    ...
    mCreateReactContextThread =
        new Thread(
            null,
            new Runnable() {
              @Override
              public void run() {
                ...
                mHasStartedCreatingInitialContext = true;

                try {
                  Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
                  ReactMarker.logMarker(VM_INIT);
                  // 创建ReactContext的入口
                  // ReactApplicationContext继承ReactContext,简单的包装了一下
                  final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());
                  ...
                  // 创建一个Runnable,封装了成功创建ReactContext后要做的事。
                  Runnable setupReactContextRunnable =
                      new Runnable() {
                        @Override
                        public void run() {
                          try {
                            setupReactContext(reactApplicationContext);
                          } catch (Exception e) {
                            // TODO T62192299: remove this after investigation
                            FLog.e(
                                ReactConstants.TAG,
                                "ReactInstanceManager caught exception in setupReactContext",
                                e);

                            mDevSupportManager.handleException(e);
                          }
                        }
                      };
									// 在NativeModule线程中,执行setupReactContextRunnable
                  reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
                  UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
                } catch (Exception e) {
                  mDevSupportManager.handleException(e);
                }
              }
            },
            "create_react_context");
    mCreateReactContextThread.start();
  }

可以看到最终是调用了createReactContext方法,然后创建一个Runnable,封装了成功创建ReactContext后要做的事。我们来看看创建ReactContext的核心方法。

ReactInstanceManager.java#createReactContext

private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
    ...
    // 创建ReactApplicationContext对象
    ReactApplicationContext reactContext = new ReactApplicationContext(this.mApplicationContext);
  
    // mPackages就是我们之前在ReactNativeHost配置的ReactPackage列表
    // processPackages方法将ReactPackage列表封装成NativeModule注册表(NativeModuleRegistry对象)
    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);

  	//创建CatalystInstanceImpl.Builder对象
    CatalystInstanceImpl.Builder catalystInstanceBuilder =
        new CatalystInstanceImpl.Builder()
            .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)// 设置NativeModule注册表
            .setJSBundleLoader(jsBundleLoader)// 设置jsBundleLoader
            .setNativeModuleCallExceptionHandler(exceptionHandler);
		...
    final CatalystInstance catalystInstance;
    try {
      //创建CatalystInstanceImpl对象
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
    }
  
  	// 将CatalystInstanceImpl对象绑定到reactContext上
    reactContext.initializeWithInstance(catalystInstance);

    if (mJSIModulePackage != null) {
      catalystInstance.addJSIModules(
          mJSIModulePackage.getJSIModules(
              reactContext, catalystInstance.getJavaScriptContextHolder()));
    }
    
  	...
      
  	// 加载jsBundle
    catalystInstance.runJSBundle();
    return reactContext;
  }

首先创建了ReactContext对象,然后创建了CatalystInstanceImpl对象并绑定到ReactContext,然后调用CatalystInstanceImpl对象的runJSBundle方法来加载jsBundle。等会再说什么是加载jsBundle,先来看看CatalystInstanceImpl对象。

2.3.1 CatalystInstanceImpl的初始化

CatalystInstanceImpl可以说承载了ReactContext的核心功能,它的初始化十分重要,我们来看看CatalystInstanceImpl在初始化做了什么。

public class CatalystInstanceImpl implements CatalystInstance {
  static {
    // 加载so库中的reactnativejni库
    ReactBridge.staticInit();
  }

  private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);

  // Access from any thread
  private final ReactQueueConfigurationImpl mReactQueueConfiguration;
  private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
  private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
  private final String mJsPendingCallsTitleForTrace =
      "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
  private volatile boolean mDestroyed = false;
  private final TraceListener mTraceListener;
  private final JavaScriptModuleRegistry mJSModuleRegistry;
  private final JSBundleLoader mJSBundleLoader;
  private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
  private final Object mJSCallsPendingInitLock = new Object();

  private final NativeModuleRegistry mNativeModuleRegistry;
  private final JSIModuleRegistry mJSIModuleRegistry = new JSIModuleRegistry();
  private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
  private final MessageQueueThread mNativeModulesQueueThread;
  private boolean mInitialized = false;
  private volatile boolean mAcceptCalls = false;

  private boolean mJSBundleHasLoaded;
  private @Nullable String mSourceURL;

  private JavaScriptContextHolder mJavaScriptContextHolder;
  private volatile @Nullable TurboModuleRegistry mTurboModuleRegistry = null;
  private @Nullable JSIModule mTurboModuleManagerJSIModule = null;

  // C++ parts,native方法
  private final HybridData mHybridData;
  private static native HybridData initHybrid(
      boolean enableRuntimeScheduler, boolean enableRuntimeSchedulerInTurboModule);
  public native CallInvokerHolderImpl getJSCallInvokerHolder();
  public native CallInvokerHolderImpl getNativeCallInvokerHolder();

  // 构造函数
  private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    ...
    mReactQueueConfiguration =
      	// 调用ReactQueueConfigurationImpl的静态方法,来创建整个通信体系要用到的线程
        ReactQueueConfigurationImpl.create(
            reactQueueConfigurationSpec, new NativeExceptionHandler());
    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
    mNativeModuleRegistry = nativeModuleRegistry; // nativeModule注册表
    mJSModuleRegistry = new JavaScriptModuleRegistry();// JavaScriptModule注册表
    mJSBundleLoader = jsBundleLoader;
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
    mTraceListener = new JSProfilerTraceListener(this);
    ...
    // native方法,初始化c++通信桥
    initializeBridge(
        new BridgeCallback(this),
        jsExecutor,
        mReactQueueConfiguration.getJSQueueThread(),
        mNativeModulesQueueThread,
        mNativeModuleRegistry.getJavaModules(this),// nativeModules中Js调用java的部分
        mNativeModuleRegistry.getCxxModules());// nativeModules中Js调用c++的部分
		...
  }
}

CatalystInstanceImpl在主要做了两件事创建通信体系要用到的线程,创建通信体系底层要用到的c++桥。

2.3.1.1 创建js线程和nativeModules线程

ReactQueueConfigurationImpl.java#create

public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
  
  private final MessageQueueThreadImpl mUIQueueThread;
  private final MessageQueueThreadImpl mNativeModulesQueueThread;
  private final MessageQueueThreadImpl mJSQueueThread;
	...

  public static ReactQueueConfigurationImpl create(
      ReactQueueConfigurationSpec spec, QueueThreadExceptionHandler exceptionHandler) {
    // 创建一个HashMap
    Map<MessageQueueThreadSpec, MessageQueueThreadImpl> specsToThreads = MapBuilder.newHashMap();

    // UI线程:主线程
    MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
    MessageQueueThreadImpl uiThread = MessageQueueThreadImpl.create(uiThreadSpec, exceptionHandler);
    specsToThreads.put(uiThreadSpec, uiThread);

    // js线程:负责执行js代码
    MessageQueueThreadImpl jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
    if (jsThread == null) {
      jsThread = MessageQueueThreadImpl.create(spec.getJSQueueThreadSpec(), exceptionHandler);
    }

    // nativeModules线程:处理nativeModules相关内容
    MessageQueueThreadImpl nativeModulesThread =
        specsToThreads.get(spec.getNativeModulesQueueThreadSpec());
    if (nativeModulesThread == null) {
      nativeModulesThread =
          MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
    }

    return new ReactQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
  }
}

用一个HashMap存MessageQueueThreadImpl对象,MessageQueueThreadImpl对象保存了线程相关的信息。

MessageQueueThreadImpl.java#create

	public static MessageQueueThreadImpl create(
      MessageQueueThreadSpec spec, QueueThreadExceptionHandler exceptionHandler) {
    switch (spec.getThreadType()) {
      case MAIN_UI:
        // 直接使用mainLooper创建MessageQueueThreadImpl对象
        return createForMainThread(spec.getName(), exceptionHandler);
      case NEW_BACKGROUND:
        // 手动创建Looper和线程,然后创建MessageQueueThreadImpl对象。
        return startNewBackgroundThread(spec.getName(), spec.getStackSize(), exceptionHandler);
      default:
        throw new RuntimeException("Unknown thread type: " + spec.getThreadType());
    }
  }

MessageQueueThreadImpl.java#createForMainThread

	/** @return a MessageQueueThreadImpl corresponding to Android's main UI thread. */
  private static MessageQueueThreadImpl createForMainThread(
      String name, QueueThreadExceptionHandler exceptionHandler) {
    Looper mainLooper = Looper.getMainLooper();
    final MessageQueueThreadImpl mqt =
        new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
    ...
    return mqt;
  }

MessageQueueThreadImpl.java#startNewBackgroundThread

  private static MessageQueueThreadImpl startNewBackgroundThread(
      final String name, long stackSize, QueueThreadExceptionHandler exceptionHandler) {
    ...
    Thread bgThread =
        new Thread(
            null,
            new Runnable() {
              @Override
              public void run() {
                ...
                Looper.prepare();
								...
                Looper.loop();
              }
            },
            "mqt_" + name,
            stackSize);
    bgThread.start();
    return new MessageQueueThreadImpl(name, pair.first, exceptionHandler, pair.second);
  }
2.3.1.2 初始化c++桥
  • NativeModuleRegistry是在createReactContext()方法创建并添加module的。
  • JavaScriptModuleRegistry是在CatalystInstanceImpl的构建方法创建并添加module的。

在ReactInstanceManager的构造函数中,有这样一段代码添加了核心的JavaScriptModule

    synchronized (mPackages) {
      PrinterHolder.getPrinter()
          .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages");
      mPackages.add(
          new CoreModulesPackage(
              this,
              new DefaultHardwareBackBtnHandler() {
                @Override
                public void invokeDefaultOnBackPressed() {
                  ReactInstanceManager.this.invokeDefaultOnBackPressed();
                }
              },
              mUIImplementationProvider,
              lazyViewManagersEnabled,
              minTimeLeftInFrameForNonBatchedOperationMs));
      if (mUseDeveloperSupport) {
        mPackages.add(new DebugCorePackage());
      }
      mPackages.addAll(packages);
    }

initializeBridge方法会通过jni调用native方法完成c++侧的CatalystInstance的初始化。

private native void initializeBridge(
  ReactCallback callback, // 回调方法,CatalystInstanceImpl的静态内部类ReactCallbac
  JavaScriptExecutor jsExecutor, // 默认为空
  MessageQueueThread jsQueue, // JS线程
  MessageQueueThread moduleQueue, // nativeModules线程
  Collection<JavaModuleWrapper> javaModules, // nativeModules中Js调用java的部分
  Collection<ModuleHolder> cxxModules// nativeModules中Js调用c++的部分
);

javaModules和cxxModules会在CatalystInstanceImpl.cpp的initializeBridge方法中被打包成ModuleRegistry传入Instance.cpp中。

ModuleRegistry再通过Instance的initializeBridge方法传到NativeToJsBridge.cpp中的构造函数中然后传到JsToNativeBridge。

  • NativeToJsBridge:NativeToJsBridge是java调用js的桥梁,用来调用jsModule。

  • JsToNativeBridge:JsToNativeBridge是js调用java的桥梁,用来调用nativeModule。

2.3.2 加载jsBundle

加载Js代码本质上就是将jsBundle这个资源文件加载到内存中,加载完就意味着我们开始执行js代码,调用index.js里面的AppRegistry.registerComponent方法来完成组件的注册,但此时渲染还未开始。

AppRegistry.js#registerComponent

	registerComponent(
    appKey: string, // 组件名
    componentProvider: ComponentProvider, // 一个返回组件的函数
    section?: boolean,
  ): string {
    let scopedPerformanceLogger = createPerformanceLogger();
    // runnables是一个存放键值对的对象,可以理解成map。
    runnables[appKey] = { 
      componentProvider,
      run: (appParameters, displayMode) => {
        renderApplication( // 渲染入口方法,此时还未被调用。等run方法被调用时才开始渲染。
          componentProviderInstrumentationHook(
            componentProvider,
            scopedPerformanceLogger,
          ),
          appParameters.initialProps,
          appParameters.rootTag,
          wrapperComponentProvider && wrapperComponentProvider(appParameters),
          appParameters.fabric,
          showArchitectureIndicator,
          scopedPerformanceLogger,
          appKey === 'LogBox',
          appKey,
          coerceDisplayMode(displayMode),
          appParameters.concurrentRoot,
        );
      },
    };
    if (section) {
      sections[appKey] = runnables[appKey];
    }
    return appKey;
  },

CatalystInstanceImpl是怎么加载jsBundle的呢?

CatalystInstanceImpl.java#runJSBundle

public void runJSBundle() {
    ...
    // 传入CatalystInstanceImpl对象
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
		...
  }

内部直接调用mJSBundleLoader的loadScript,mJSBundleLoade就是在前面的ReactInstanceManagerBuilder.java#build中调用JSBundleLoader.createAssetLoader创建的。

JSBundleLoader.java#createAssetLoader

public abstract class JSBundleLoader {
  public static JSBundleLoader createAssetLoader(
      final Context context, final String assetUrl, final boolean loadSynchronously) {
    return new JSBundleLoader() {
      @Override
      public String loadScript(JSBundleLoaderDelegate delegate) {
        delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
        return assetUrl;
      }
    };
  }
  ...
}

总共有三种加载jsBundle的方式:

  • setSourceURLs(String deviceURL, String remoteURL) :从远程服务器加载
  • loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously):从Assets文件夹加载
  • loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously):从文件路径加载

观察创建ReactInstanceManager的部分就会知道,dev模式下会从远程服务下载,默认是使用第二种加载Assets文件夹下的"index.android.bundle"文件,如果同时配置了第二和第三种,第三种优先级更高。

loadScript方法的参数是JSBundleLoaderDelegate对象,而前面传入了CatalystInstanceImpl对象,不出意外CatalystInstanceImpl就是

JSBundleLoaderDelegate对象。

public class CatalystInstanceImpl implements CatalystInstance {}
public interface CatalystInstance extends MemoryPressureListener, JSInstance, JSBundleLoaderDelegate {}

是了是了,也就是说加载jsBundle最终调用了CatalystInstanceImpl的loadScriptFromAssets方法

CatalystInstanceImpl.java#loadScriptFromAssets

	private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
	
	@Override
  public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {
    mSourceURL = assetURL;
    jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
  }

最终加载jsBundle是通过jni的方式,调用了native方法jniLoadScriptFromAssets。(这里的native指的是c/c++)

在c++层完成加载jsBundle后,会进入MessageQueue.js开始执行js代码。

2.4 setupReactContext

前面说到创建万ReactContext后还要调用setupReactContext方法

ReactInstanceManager.java#setupReactContext

	private void setupReactContext(final ReactApplicationContext reactContext) {
    ...
    synchronized (mAttachedReactRoots) {
      synchronized (mReactContextLock) {
        mCurrentReactContext = Assertions.assertNotNull(reactContext);
      }

      CatalystInstance catalystInstance =
          Assertions.assertNotNull(reactContext.getCatalystInstance());

      catalystInstance.initialize();

      ...
      for (ReactRoot reactRoot : mAttachedReactRoots) {
        if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) {
          // 将ReactRoot绑定到ReactInstanceManager
          attachRootViewToInstance(reactRoot);
        }
      }
    }
    ...
  }

ReactInstanceManager.java#attachRootViewToInstance

	private void attachRootViewToInstance(final ReactRoot reactRoot) {

    @Nullable
    UIManager uiManager =
        UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());

    ...

    // ReactRootView.startApplication传的mLaunchOptions
    @Nullable Bundle initialProperties = reactRoot.getAppProperties();

    final int rootTag;

    if (reactRoot.getUIManagerType() == FABRIC) {
      rootTag =
          uiManager.startSurface(
              reactRoot.getRootViewGroup(),
              reactRoot.getJSModuleName(),
              initialProperties == null
                  ? new WritableNativeMap()
                  : Arguments.fromBundle(initialProperties),
              reactRoot.getWidthMeasureSpec(),
              reactRoot.getHeightMeasureSpec());
      reactRoot.setRootViewTag(rootTag);
      reactRoot.setShouldLogContentAppeared(true);
    } else {
      // 将ReactRootView添加到UIManager上,会返回一个int型的rootTag来标识ReactRootView
      rootTag =
          uiManager.addRootView(
              reactRoot.getRootViewGroup(),
              initialProperties == null
                  ? new WritableNativeMap()
                  : Arguments.fromBundle(initialProperties),
              reactRoot.getInitialUITemplate());
      reactRoot.setRootViewTag(rootTag);
      // 启动ReactRootView
      reactRoot.runApplication();
    }
		...
  }

ReactRootView.java#runApplication

public void runApplication() {
    try {
      if (mReactInstanceManager == null || !mIsAttachedToInstance) {
        return;
      }

      ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
      if (reactContext == null) {
        return;
      }

      CatalystInstance catalystInstance = reactContext.getCatalystInstance();
      // 获取主组件名
      String jsAppModuleName = getJSModuleName();

      if (mWasMeasured) {
        updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec);
      }

      WritableNativeMap appParams = new WritableNativeMap();
      // 打包rootTag和appProperties到appParams
      appParams.putDouble("rootTag", getRootViewTag());
      @Nullable Bundle appProperties = getAppProperties();
      if (appProperties != null) {
        appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
      }

      mShouldLogContentAppeared = true;

      // 调用AppRegistry这个JavaScriptModule的runApplication方法,传入主组件名和参数
      catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

至此就到达了进入js世界的入口,也就是调用了js代码的AppRegistry.runApplication方法。正式开始渲染rn组件。

AppRegistry.js#runApplication

	runApplication(
    appKey: string,
    appParameters: any,
    displayMode?: number,
  ): void {
    ...
    runnables[appKey].run(appParameters, displayMode);// 取出之前注册的对象,执行run方法
  },

来看前面注册时,run方法内部的renderApplication方法:

renderApplication.js#renderApplication

function renderApplication<Props: Object>(
  RootComponent: React.ComponentType<Props>,
  initialProps: Props,
  rootTag: any,
  WrapperComponent?: ?React.ComponentType<any>,
  fabric?: boolean,
  showArchitectureIndicator?: boolean,
  scopedPerformanceLogger?: IPerformanceLogger,
  isLogBox?: boolean,
  debugName?: string,
  displayMode?: ?DisplayModeType,
  useConcurrentRoot?: boolean,
) {
  ...
  let renderable = (
    <PerformanceLoggerContext.Provider value={performanceLogger}>
      <AppContainer
        rootTag={rootTag}
        fabric={fabric}
        showArchitectureIndicator={showArchitectureIndicator}
        WrapperComponent={WrapperComponent}
        initialProps={initialProps ?? Object.freeze({})}
        internal_excludeLogBox={isLogBox}>
        <RootComponent {...initialProps} rootTag={rootTag} /> // 这里的RootComponent就是前面注册的组件,这里将原生传过来的initialProps和rootTag作为属性传给RootComponent
      </AppContainer>
    </PerformanceLoggerContext.Provider>
  );
	...
  if (fabric) {
    require('../Renderer/shims/ReactFabric').render(
      renderable,
      rootTag,
      null,
      useConcurrentRoot,
    );
  } else {
    require('../Renderer/shims/ReactNative').render(renderable, rootTag);
  }
  ...
}

至此组件开始渲染,先写到这。水平有限,对源码的阅读可能会出错,请多多理解。