转载

从 Hello World 看 RN 的启动流程

前言

第一次接触 React Native 是在四年前实习的时候,当时在项目中使用的 RN 版本是 0.28.x ,间隔四年之后,再次在项目中使用 RN 时版本已是 0.57.x 。在撰写本文时,RN 的版本是 0.60.4 ,所以,本文将以 0.60.4 版本为基础,简要分析 RN 应用在 Android 平台上的启动流程

Hello World

用 RN 来写一个 Hello World 应用非常简单。通过 RN cli 生成项目之后,更改程序的入口文件即可:

import { Text, AppRegistry } from 'react-native'
import App from './App'

// ...
AppRegistry.registerComponent('HelloWorld', () => App);

程序的入口文件一般是通过 AppRegistry 对 RN 应用进行注册, registerComponent 的实现如下:

// react-native/Libraries/ReactNative/AppRegistry.js

// ...
// 类型声明
export type ComponentProvider = () => React$ComponentType<any>;
export type Runnable = {
  component?: ComponentProvider,
  run: Function,
};
export type Runnables = {
  [appKey: string]: Runnable,
};

// 保存注册过的应用
const runnables: Runnables = {};

// ...
// 注册应用的根组件
registerComponent(
    appKey: string,
    componentProvider: ComponentProvider,
    section?: boolean,
  ): string {
    
    runnables[appKey] = {
      componentProvider,
      /** 
      * appParameters 是原生端初始化 RN 应用时透传的参数
      * 属性主要包含用于初始化的 initialProps,rootTag,fabric等
      */
      run: appParameters => {
        renderApplication(
          // ...
        )
      },
    };
    
    // ...
    return appKey;
  },
// ...

registerComponent 方法的第一个参数是 appKey ,第二个参数是与之对应的根组件。因而如果要注册多个 RN 应用,就需要确保 appKey 的值是唯一的,因为原生端也是依赖 appKey 来启动对应的 RN 应用的。

那么,在 JavaScript 端注册 HelloWorld 应用之后,原生端是怎么启动 HelloWorld 的呢?

启动流程

通过 RN cli 新建 Hello 项目之后,不仅会生成 JavaScript 代码,也会创建与之对应的原生工程项目。对于 Android 工程而言,会生成两个主要的类: MainActivityMainApplication ,这是 Android 应用的启动入口。

先看下 MainActivity 的实现:

// ...
public class MainActivity extends ReactActivity {

  @Override
  protected String getMainComponentName() {
    return "HelloWorld";
  }
}

MainActivity 继承了 ReactActivity ,并重写了 getMainComponentName 方法,而这个方法就是返回在 JavaScript 端注册的 appKey

然后再看下 MainApplication 的实现:

// ...
public class MainApplication extends Application implements ReactApplication {
  // 创建 ReactNativeHost 的匿名子类实例
  private final ReactNativeHost mReactNativeHost =
      new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          // 是否开启 dev mode
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          /**
          * 返回原生依赖的包列表
          * 实际开发中,js 端会对原生端有依赖,当原生端把依赖暴露给 RN 时,需要在这手动添加原生包
          * 在后续的流程中,会把所有的原生依赖在 C++ 层进行注册,供 js 端调用
          * packages.add(new MyReactNativePackage())
          */
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          // 返回主模块名,默认为 index
          return "index";
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    /**
    * 初始化 Soloader(https://github.com/facebook/SoLoader)
    * 在一个 RN 应用中,牵涉到 js 和 Native(C/C++) 的通信(JSC/JSI),Java 和 Native(C/C++) 的通信(JNI)
    * 以及 js 和 Java 之间的通信(转嫁到 C++ 上)
    * 而 Soloader 就是一个 Native Code(主要是c/c++) 的 loader,用于加载和解析动态链接库,为后续的通信作准备
    */
    SoLoader.init(this, /* native exopackage */ false);
  }
}

MainApplication 实现了接口 ReactApplication ,主要是实现其 getReactNativeHost 方法:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactApplication.java

package com.facebook.react;

public interface ReactApplication {

  /** Get the default {@link ReactNativeHost} for this app. */
  ReactNativeHost getReactNativeHost();
}

ReactNativeHost 是 RN 应用的宿主类,其本身是一个抽象类,在创建 ReactNativeHost 实例时,重写了里面的两个抽象方法:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java

// ...
public abstract class ReactNativeHost {

  private final Application mApplication;
  private @Nullable ReactInstanceManager mReactInstanceManager;

  protected ReactNativeHost(Application application) {
    // 保存 app 应用实例
    mApplication = application;
  }

  /** 
  * 返回 ReactInstanceManager 实例
  * 这个方法会在 ReactDelegate#loadApp 方法中被调用
  * 其返回值赋值给 ReactRootView#startReactApplication 方法的第一个参数
  */
  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      // 略去日志代码
      // 实例不存在则创建实例
      mReactInstanceManager = createReactInstanceManager();
      // 略去日志代码
    }
    return mReactInstanceManager;
  }
  
  // ...
 
  // 创建 ReactInstanceManager 实例
  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    /**
    * 类 ReactInstanceManagerBuilder 提供了很多 set 方法来保存创建
    * ReactInstanceManager 实例相关的上下文信息
    */
    ReactInstanceManagerBuilder builder =
        ReactInstanceManager.builder()
            // 应用上下文
            .setApplication(mApplication)
            // 设置MainModuleName,相当于应用首页的 js bundle
            .setJSMainModulePath(getJSMainModuleName())
            // 是否开启dev模式
            .setUseDeveloperSupport(getUseDeveloperSupport())
            // 设置红盒的回调(dev 模式下才有红屏显示)
            .setRedBoxHandler(getRedBoxHandler())
            // 设置 js 的执行器工厂实例,为后续加载和解析 js bundle 作准备
            .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
            // 设置UI实现机制的Provider
            .setUIImplementationProvider(getUIImplementationProvider())
            // 设置 JSI Module:js -->C++(JSI)-->Java Module
            .setJSIModulesPackage(getJSIModulePackage())
            // 初始化 host 的生命周期状态
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
    
    // 添加原生依赖包
    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }
    
    /** 
    * 获取js Bundle的加载路径
    * 如果没有自定义加载路径,就从 Android assets 中加载 index.android.bundle 文件
    * 默认路径是:assets:// + getBundleAssetName 方法的返回值
    */
    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;
  }

  // RedBox 相关的回调
  protected @Nullable RedBoxHandler getRedBoxHandler() {
    return null;
  }

  // 如果要自定义 js 执行器,重写该方法
  protected @Nullable JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
    return null;
  }

  protected final Application getApplication() {
    return mApplication;
  }

  // 如果需要自定义UI实现机制,可重写该方法,但99%的情况下不需要,使用默认机制就行
  protected UIImplementationProvider getUIImplementationProvider() {
    return new UIImplementationProvider();
  }

  protected @Nullable JSIModulePackage getJSIModulePackage() {
    return null;
  }


  /** 
  * 返回主模块名
  * 返回值决定了从服务器拉取 js bundle 的 URL,仅在开发模式下有用
  */    
  protected String getJSMainModuleName() {
    return "index.android";
  }
  
  
  /** 
  * 返回 js bundle 文件的路径
  * 如果需要自定义路径,需要在子类中重写这个方法
  * 默认会从 Android assets 中加载 js bundle
  * 文件路径类似于 "file://sdcard/myapp_cache/index.android.bundle"
  */
  protected @Nullable String getJSBundleFile() {
    return null;
  }
  
  // 返回 Android assets 中的 js bundle 名称
  protected @Nullable String getBundleAssetName() {
    return "index.android.bundle";
  }
  
  // 是否开启dev模式
  public abstract boolean getUseDeveloperSupport();

  // 返回app需要的ReactPackage,包含了运行时需要用到的NativeModule/JavaScriptModule等
  protected abstract List<ReactPackage> getPackages();
}

虽然在 ReactDelegate#loadApp 方法被调用时才创建 ReactInstanceManager 实例,但我们简单看下其创建的参数列表,这有利于后文的理解。

ReactInstanceManagerBuilder#build 方法的实现如下:

// react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java

// ...

import static com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getFriendlyDeviceName;

// ...

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
    String appName = mApplication.getPackageName();
    String deviceName = getFriendlyDeviceName();
    
    return new ReactInstanceManager(
        mApplication,
        mCurrentActivity,
        mDefaultHardwareBackBtnHandler,
        mJavaScriptExecutorFactory == null
            ? getDefaultJSExecutorFactory(appName, deviceName)
            : mJavaScriptExecutorFactory,
        (mJSBundleLoader == null && mJSBundleAssetUrl != null)
            ? JSBundleLoader.createAssetLoader(
                mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
            : mJSBundleLoader,
        mJSMainModulePath,
        mPackages,
        mUseDeveloperSupport,
        mBridgeIdleDebugListener,
        Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
        mUIImplementationProvider,
        mNativeModuleCallExceptionHandler,
        mRedBoxHandler,
        mLazyViewManagersEnabled,
        mDevBundleDownloadListener,
        mMinNumShakes,
        mMinTimeLeftInFrameForNonBatchedOperationMs,
        mJSIModulesPackage,
        mCustomPackagerCommandHandlers);
}

private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName) {
    try {
      // 加载 C++ 层的 jscexecutor
      SoLoader.loadLibrary("jscexecutor");
      return new JSCExecutorFactory(appName, deviceName);
    } catch (UnsatisfiedLinkError jscE) {
      // Otherwise use Hermes
      return new HermesExecutorFactory();
    }
  }
// ...

重点需要关注两点:

  1. mJSBundleLoader 的初始化: JSBundleLoader 是一个抽象类,但根据不同的 bundle 加载场景,提供了不同的静态方法来创建匿名子类实例。上文说到,可以通过重写 ReactNativeHost#getJSBundleFile 方法自定义 bundle 的加载路径。如果 bundle 路径不是以 assets:// 开头,则会通过 JSBundleLoader 类的静态方法 createFileLoader 创建一个实例;反之,则会通过其静态方法 createAssetLoader 创建一个实例。

  2. mJavaScriptExecutorFactory 的初始化:通过上文可知, ReactNativeHost#getJavaScriptExecutorFactory 返回值是 null ,因而会调用 getDefaultJSExecutorFactory 方法创建默认的 js 执行器工厂实例。

接下来看看 ReactActivity 的实现。

ReactActivity

从上文可知, MainActivity 继承了 ReactActivity ,并重写了 getMainComponentName 方法。 ReactActivity 是一个抽象类,其主要实现如下:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java

// ...
public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
 
  // 声明 ReactActivityDelegate 实例变量
  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    // 在构造函数中创建 ReactActivityDelegate 实例
    mDelegate = createReactActivityDelegate();
  }
  
  // 在子类 MainActivity 中重写了该方法,返回 js 端注册的 appKey
  protected @Nullable String getMainComponentName() {
    return null;
  }

  protected ReactActivityDelegate createReactActivityDelegate() {
    // 创建 ReactActivityDelegate 实例
    return new ReactActivityDelegate(this, getMainComponentName());
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }
  
  //...
  
  // 获取 ReactNativeHost 实例
  protected final ReactNativeHost getReactNativeHost() {
    return mDelegate.getReactNativeHost();
  }
  
  // 获取 ReactInstanceManager 实例    
  protected final ReactInstanceManager getReactInstanceManager() {
    return mDelegate.getReactInstanceManager();
  }
  
  // 加载 RN App
  protected final void loadApp(String appKey) {
    mDelegate.loadApp(appKey);
  }
}

ReactActivity 本身是一个抽象类,没有具体的功能实现,其主要作用有两个:

  1. 提供 getMainComponentName 方法的声明
  2. 创建 ReactActivityDelegate 实例,便于把具体的功能全委托给 ReactActivityDelegate 类来处理

ReactActivityDelegate

ReactActivityDelegate 类的主要实现如下:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java

// ...
public class ReactActivityDelegate {
  private final @Nullable Activity mActivity;
  private final @Nullable String mMainComponentName;
  // ...
  private ReactDelegate mReactDelegate;
  
  // 构造函数
  public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
    mActivity = activity;
    mMainComponentName = mainComponentName;
  }
  
  /**
  * 获取 bundle 初始化的 props
  * 如果需要初始化的 props,需要 Android 实现一个子类并重写这个方法或者自定义实现 ReactActivityDelegate
  * 该方法的返回值会赋值给 js 端 run 方法的参数appParameters#initialProps
  */
  protected @Nullable Bundle getLaunchOptions() {
    return null;
  }
    
  // 获取 ReactRootView 实例 
  protected ReactRootView createRootView() {
    return mReactDelegate.createRootView();
  }
  
  /**
  * 获取当前应用使用的 ReactNativeHost 实例
  * 上文有说到,在 ReactNativeHost 的实例是在 MainApplication 中创建的 
  */    
  protected ReactNativeHost getReactNativeHost() {
    return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
  }
  
  // 获取 ReactInstanceManager 实例
  public ReactInstanceManager getReactInstanceManager() {
    return mReactDelegate.getReactInstanceManager();
  }
  
  // 获取 appKey    
  public String getMainComponentName() {
    return mMainComponentName;
  }

  protected void onCreate(Bundle savedInstanceState) {
    String mainComponentName = getMainComponentName();
    // 创建 ReactDelegate 实例
    mReactDelegate =
        new ReactDelegate(
            getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions());
    if (mMainComponentName != null) {
      // 开启加载应用
      loadApp(mainComponentName);
    }
  }

  protected void loadApp(String appKey) {
    // 实际是调用 ReactDelegate 实例的 loadApp 方法启动 RN 应用
    mReactDelegate.loadApp(appKey);
    // 调用Activity 的setContentView()方法,将根视图添加到当前的Activity
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  }
  
  // ...
  
  protected Context getContext() {
    return Assertions.assertNotNull(mActivity);
  }

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

ReactActivityDelegate 类主要是在其生命周期的 onCreate 方法中做了三件事:创建 ReactDelegate 实例、调用 ReactActivityDelegate#loadApp 开始启动 RN 应用以及设置当前 Activity 的根视图。

ReactDelegate

ReactDelegate 类的实现比较简单,关键部分代码如下:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java

// ...
public class ReactDelegate {
    
  // ...
  
  // 构造函数
  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(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    // 创建 RN 容器根视图
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
        // 这里会去创建 ReactInstanceManager 实例
        getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
  }

  public ReactRootView getReactRootView() {
    return mReactRootView;
  }

  protected ReactRootView createRootView() {
    return new ReactRootView(mActivity);
  }
   
  // ...
  
  private ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

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

ReactDelegate#loadApp 方法主要做了两件事:创建 RootView 和开始启动 React App。

ReactRootView

ReactRootView 是一个自定义的 View,其父类是 FrameLayout ,代码量比较大,因而我们只顺着上面的思路看一下 startReactApplication 的实现:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

// ...
public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
  // ...
  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties,
      @Nullable String initialUITemplate) {
    // ...
    try {
      // 断言:如果当前线程不是 UI 线程的话,就会抛出 Expected to run on UI thread! 的错误
      UiThreadUtil.assertOnUiThread();

      Assertions.assertCondition(
          mReactInstanceManager == null,
          "This root view has already been attached to a catalyst instance manager");
      
      // 赋值
      mReactInstanceManager = reactInstanceManager;
      mJSModuleName = moduleName;
      mAppProperties = initialProperties;
      mInitialUITemplate = initialUITemplate;
      
      // mUseSurface 是在构造函数中被赋值的   
      if (mUseSurface) {
        // TODO initialize surface here
      }
      
      /**
      * 在后台任务中触发 react context 的初始化(异步)
      * 此时会去预加载 js,并在 UI 的布局完成之前执行全局代码
      */    
      mReactInstanceManager.createReactContextInBackground();
      
      // 将 RootView 附加到 ReactInstanceManager 的成员变量 mAttachedReactRoots 中
      // 后文会再提到 mAttachedReactRoots
      attachToReactInstanceManager();

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

接下来我们看 ReactInstanceManager 对应代码的实现。

ReactInstanceManager

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

  // ...
  public void createReactContextInBackground() {
    //略去日志输出代码
    
    // UI 线程断言
    UiThreadUtil.assertOnUiThread(); 
    
    // 是否已经初始化的判断
    if (!mHasStartedCreatingInitialContext) {
      mHasStartedCreatingInitialContext = true;
      recreateReactContextInBackgroundInner();
    }
  }
  
  /**
   * Recreate the react application and context. This should be called if configuration has changed
   * or the developer has requested the app to be reloaded. It should only be called after an
   * initial call to createReactContextInBackground.
   */
  @ThreadConfined(UI)
  public void recreateReactContextInBackground() {
    // ...
    
    recreateReactContextInBackgroundInner();
  }
  // ...

从代码中可以看到, createReactContextInBackground 在 Application 中只会被调用一次。当应用配置或者应用重新加载时,需要重新创建 ReactContext 信息,此时是去调用 公开的 recreateReactContextInBackground 方法(注意:该方法有一个 私有的 实现,后续会提到)。但两个方法最终调用的实际都是 recreateReactContextInBackgroundInner 方法:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

  // ...
  private void recreateReactContextInBackgroundInner() {
    // ...
    
    // 断言
    UiThreadUtil.assertOnUiThread();
    
    // 开发模式
    if (mUseDeveloperSupport && mJSMainModulePath != null) {
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
        
      /**
      * 省略代码
      * 从上面条件的判断可以得知,这里主要是处理开发模式下,会从本地的服务器加载 bundle
      */

    }
    
    // 线上模式
    recreateReactContextInBackgroundFromBundleLoader();
  }
  
  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    // 省略输出日志的代码
    // 调用私有实现
    recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
  }
  
  // ...
  @ThreadConfined(UI)
  private void recreateReactContextInBackground(
      JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
      
    // ...
    
    // 断言
    UiThreadUtil.assertOnUiThread();
    
    /** 
    * ReactContextInitParams 是一个私有类
    * 主要是初始化类的 mJsExecutorFactory 和 mJsBundleLoader
    * 后文会具体提到 ReactContextInitParams 类
    */
    final ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    if (mCreateReactContextThread == null) {
      // 开启新线程创建react context
      runCreateReactContextOnNewThread(initParams);
    } else {
      //创建 ReactContext 的后台任务已经开启,缓存initParams在队列中等待重新创建 ReactContext
      mPendingReactContextInitParams = initParams;
    }
  }
  
  // ...

recreateReactContextInBackground 方法的私有实现中,有两个形参: jsExecutorFactoryjsBundleLoader

  • jsExecutorFactory:js 执行器工厂实例,作为 C++ 和 js 双向通信的桥梁
  • jsBundleLoader:加载器实例,用于加载 js bundle

接着往下看 runCreateReactContextOnNewThread 的实现:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...

  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
      // ...
      
      // 创建一个新线程
      mCreateReactContextThread = new Thread (
       null,
       new Runnable () {
          @Override
          public void run () {
             // ...
             
             try {
                // 设置当前线程的优先级
                Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
                // 创建 ReactContext 
                final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());

                mCreateReactContextThread = null;
                // ...
                
                Runnable setupReactContextRunnable =
                      new Runnable() {
                        @Override
                        public void run() {
                          try {
                            // 后文会再提到这行代码
                            setupReactContext(reactApplicationContext);
                          } catch (Exception e) {
                            mDevSupportManager.handleException(e);
                          }
                        }
                      };
                
                // 开启线程运行 setupReactContextRunnable        
                reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
                UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
             } catch (Exception e) {
                // ...
             }
          }
       }
      )
      
      // 启动线程
      mCreateReactContextThread.start();
  }

// ...

runCreateReactContextOnNewThread 方法的核心是调用 createReactContext 方法来创建 React Context:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...
  private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
    
    // 略去日志输出代码
    
    /** 
    * 传入 Android Application 的实例去创建 ReactContext 实例
    * ReactApplicationContext 继承自 ReactContext,仅仅是简单包装了一下
    * Android Application,全部的功能都在 ReactContext 类中实现
    */
    final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
    
    // 设置 Native Module 调用的异常处理器
    NativeModuleCallExceptionHandler exceptionHandler =
        mNativeModuleCallExceptionHandler != null
            ? mNativeModuleCallExceptionHandler
            : mDevSupportManager;
    reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
    
    /** 
    * 创建 Native Module 注册表,将Java可调用的API暴露给 js
    * mPackages 在创建 ReactInstanceManager 实例时已被初始化
    */
    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
    
    // 先处理 jsExecutor/nativeModuleRegistry/jsBundleLoader 等参数,便于后续构建 CatalystInstance 实例
    CatalystInstanceImpl.Builder catalystInstanceBuilder =
        new CatalystInstanceImpl.Builder()
            // 设置 React 队列配置(UI、js、native modules 三个线程队列)
            .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            .setJSBundleLoader(jsBundleLoader)
            .setNativeModuleCallExceptionHandler(exceptionHandler);

    // 略去日志输出代码
    
    final CatalystInstance catalystInstance;
    try {
      // 创建 CatalystInstance 实例
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      // 略去日志输出代码
    }
    
    // 初始化 ReactContext 的队列配置(UI、js、native modules 三个线程队列)
    reactContext.initializeWithInstance(catalystInstance);
    
    /**
    * 初始化 JSI(JavaScript Interface)
    * JSI & JSC 的讨论:https://github.com/react-native-community/discussions-and-proposals/issues/91
    * 从上文可知,mJSIModulePackage 的值是 null
    */
    if (mJSIModulePackage != null) {
      catalystInstance.addJSIModules(
          mJSIModulePackage.getJSIModules(
              reactContext, catalystInstance.getJavaScriptContextHolder()));
      
      //TurboModules : https://github.com/react-native-community/discussions-and-proposals/issues/40
      if (ReactFeatureFlags.useTurboModules) {
        catalystInstance.setTurboModuleManager(
            catalystInstance.getJSIModule(JSIModuleType.TurboModuleManager));
      }
    }
    
    // 略去日志输出代码
    
    // 开始加载 js Bundle
    catalystInstance.runJSBundle();
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    return reactContext;
  }
// ...

createReactContext 方法主要作了如下四件事:

  • 创建 NativeModule 注册表,并交由 CatalystInstance 管理
  • 创建 CatalystInstance 实例
  • 如果存在 JSI Module,就对其进行注册
  • 关联 ReactContext 和 CatalystInstance,并开始加载 js bundle

CatalystInstance 是一个接口类型,定义了一系列 JSC(JavaScript Core) Bridge API 接口,提供了允许(从 Java 层)调用 JS 方法的环境,同时提供了部分 Java API 供 JS 层调用,其具体实现是 CatalystInstanceImpl 类。

下一篇 我们继续接着分析 CatalystInstanceImpl 类。

原文  https://github.com/dwqs/blog/issues/75
正文到此结束
Loading...