React Native 启动流程 源码剖析

开始之前

  开始分析之前,新建一个名为 RnDemo 的空项目,RN 版本选择 0.58.1,查看项目自动为我们生成 MainActivity.java 和 MainApplication.java 文件,我们的分析就从这两个文件入手。

源码结构图

  "react-native": "^0.58.1", "react": "^16.6.3",
在这里插入图片描述

系统框架图

在这里插入图片描述

源码剖析

1、MainApplication

  继承 Application 并实现了 ReactApplication 接口,主要做一些 RN 的初始化操作。该接口要求创建一个 ReactNativeHost 对象。ReactNativeHost 对象,本身持有 ReactInstanceManager 对象。

public class MainApplication extends Application implements ReactApplication {
  // 实现 ReactApplication 接口,创建 ReactNativeHost 成员变量
  // 持有 ReactInstanceManager 实例,做一些初始化操作。
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
  // 是否开启 dev 调试,及一些调试工具,比如 redbox(红盒),有时我们看到的报错
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }
    // 返回 app 需要的 ReactPackage,添加需要加载的模块,
    // 这个地方就是我们在项目中添加依赖包时需要添加第三方 package 的地方
    @Override 
    protected List<ReactPackage> getPackages() {
      @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() {
      return "index";
    }
  };

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

  @Override
  public void onCreate() {
    super.onCreate();
    // SoLoader:加载 C++ 底层库,准备解析 JS。
    SoLoader.init(this, /* native exopackage */ false);
  }
}

  其中,ReactNativeHost 主要的工作就是创建 ReactInstanceManager,创建部分代码如下

public abstract class ReactNativeHost {
  protected ReactInstanceManager createReactInstanceManager() {
    // Builder 模式,创建 ReactInstanceManager 实例
    ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
      // 设置应用上下文
      .setApplication(mApplication)
      // 设置应用的 jsBundle,可以传给 url 来使其从服务器拉去 jsBundle
      // 仅在 dev 下生效
      .setJSMainModulePath(getJSMainModuleName())
      // 是否开启 dev 模式
      .setUseDeveloperSupport(getUseDeveloperSupport())
      // 红盒回调
      .setRedBoxHandler(getRedBoxHandler())
      .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
      // 自定义 UI 实现机制,不会使用
      .setUIImplementationProvider(getUIImplementationProvider())
      .setJSIModulesPackage(getJSIModulePackage())
      .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
    // 添加 ReactPackage (就是我们复写的抽象方法)
    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }
    // 获取 js Bundle 的加载路径
    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    // 创建
    ReactInstanceManager reactInstanceManager = builder.build();
    return reactInstanceManager;
  }
}

2、MainActivity

  继承自 ReactActivity,ReactActivity 作为 JS 页面的真正容器

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 入口注册名字一致
        return "RnDemo";
    }
}
// 对应的 js 组件注册名字:
import { AppRegistry } from 'react-native'
// ...省略代码
AppRegistry.registerComponent("RnDemo", () => App);

3、ReactActivity

public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {

  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    mDelegate = createReactActivityDelegate();
  }
  
  /**
   * Returns the name of the main component registered from JavaScript.
   * This is used to schedule rendering of the component.
   * e.g. "MoviesApp"
   */
  protected @Nullable String getMainComponentName() {
    return null;
  }
  
  /**
   * Called at construction time, 
   * override if you have a custom delegate implementation.
   */
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName());
  }
  ...
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }
  
  protected final ReactNativeHost getReactNativeHost() {
    return mDelegate.getReactNativeHost();
  }

  protected final ReactInstanceManager getReactInstanceManager() {
    return mDelegate.getReactInstanceManager();
  }

  protected final void loadApp(String appKey) {
    mDelegate.loadApp(appKey);
  }
}

  从以上代码可以看到,ReactActivity 全权委托给 ReactActivityDelegate 来处理,也就是说真正的实现是在 ReactActivityDelegate 类中进行的。

4、ReactActivityDelegate

public class ReactActivityDelegate {
  protected void onCreate(Bundle savedInstanceState) {
    // mMainComponentName 就是上面 ReactActivity.getMainComponentName()
    if (mMainComponentName!= null) {
      // 加载 app 页面
      loadApp(mMainComponentName);
    }
     // 双击判断工具类
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

  protected void loadApp(String appKey) {
    // 非空判断
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    // 创建 ReactRootView 作为根视图,它本质上是一个 FrameLayout
    mReactRootView = createRootView();
    // 启动 RN 应用,并完成一些初始化设置
    mReactRootView.startReactApplication( // 分析
      getReactNativeHost().getReactInstanceManager(),appKey, getLaunchOptions());
    
    // 将 ReactRootView 作为 Activity 的显示 view
    getPlainActivity().setContentView(mReactRootView);
  }
}

  可以发现,ReactActivityDelegate(loadApp()) 主要做了三个工作:

  • 创建 ReactRootView 作为应用的根视图
  • startReactApplication 启动 RN 流程
  • 将 ReactRootView 作为 ReactActivity 的内容显示 view

5、ReactRootView

  ReactRootView 是个核心关键,本质上是一个 FrameLayout,进入 ReactRootView 类继续看一下启动 RN 的 startReactApplication() 方法,它接受四个参数:ReactInstanceManager,moduleName,initialProperties,initialUITemplate。

public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties,
      @Nullable String initialUITemplate) {
      // ...省略代码
    try {
       // 确保在 UI 线程执行
       UiThreadUtil.assertOnUiThread();
      // reactInstanceManager 实例,管理 React 实例
      mReactInstanceManager = reactInstanceManager;
      mJSModuleName = moduleName;

      mAppProperties = initialProperties;
      mInitialUITemplate = initialUITemplate;
      
      // 创建 RN 的上下文 ReactContext
      if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
        mReactInstanceManager.createReactContextInBackground(); // 分析
      }
      
      // 宽高计算完成后添加布局监听
      attachToReactInstanceManager();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

6、ReactInstanceManger

进入 ReactInstanceManger 类看一下 createReactContextInBackground() 方法。

/**
   * Trigger react context initialization asynchronously in a background async task. This enables
   * applications to pre-load the application JS, and execute global code before
   * {@link ReactRootView} is available and measured. This should only be called the first time the
   * application is set up, which is enforced to keep developers from accidentally creating their
   * application multiple times without realizing it.
   *
   * Called from UI thread.
   */
  @ThreadConfined(UI)
  public void createReactContextInBackground() {
  	// 省略。。。
    // 仅在应用首次启动时调用,防止开发人员意外的创建其他应用
    mHasStartedCreatingInitialContext = true;
    recreateReactContextInBackgroundInner(); // 分析
  }

7、recreateReactContextInBackgroundInner

  createReactContextInBackground 方法仅会在首次启动时调用,重新加载 (reloaded)app 时,会调用 recreateReactContextInBackground(),两个方法都会调用 recreateReactContextInBackgroundInner()。

@ThreadConfined(UI)
  private void recreateReactContextInBackgroundInner() {
    //...省略// 
    // UI 线程
    UiThreadUtil.assertOnUiThread();
    // 开发模式,实现在线更新 Bundle,
    // 晃动弹出调试菜单等功能,这一部分属于调试功能流程。
    if (mUseDeveloperSupport && mJSMainModulePath != null) {
      final DeveloperSettings devSettings = 
          mDevSupportManager.getDevSettings();

      // If remote JS debugging is enabled, load from dev server.
      if (mDevSupportManager.hasUpToDateJSBundleInCache() &&
          !devSettings.isRemoteJSDebugEnabled()) {
        // If there is a up-to-date bundle downloaded from server,
        // with remote JS debugging disabled, always use that.
        // 调试模式,从服务器加载 jsBundle
        onJSBundleLoadedFromServer(null);
        return;
      }

      if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
        // 加载服务 bundle
        if (mBundleLoader == null) {
          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 dev server is down, disable the remote JS debugging.
                            devSettings.setRemoteJSDebugEnabled(false);
                            recreateReactContextInBackgroundFromBundleLoader();
                          }
                        }
                      });
                }
              });
        }
        return;
      }
    }
    // 加载本地 bundle
    recreateReactContextInBackgroundFromBundleLoader(); // 分析
  }
  
  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    recreateReactContextInBackground(new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),
        mBundleLoader); // 分析
  }

8、recreateReactContextInBackground

  recreateReactContextInBackgroundFromBundleLoader() 方法继续向下调用 recreateReactContextInBackground() 方法。

@ThreadConfined(UI)
  private void recreateReactContextInBackground(
    JavaScriptExecutorFactory jsExecutorFactory, // C++ 和 JS 双向通信的中转站
    JSBundleLoader jsBundleLoader) { // bundle 加载器,根据 ReactNativeHost 中的配置决定从哪里加载 bundle 文件
        UiThreadUtil.assertOnUiThread();
        // 创建 ReactContextInitParams 对象
        final ReactContextInitParams initParams = new ReactContextInitParams(
            jsExecutorFactory,
            jsBundleLoader);
       if (mCreateReactContextThread == null) {
       		// 在 newThread 实例化 ReactContext
       		runCreateReactContextOnNewThread(initParams);
       } else {
            mPendingReactContextInitParams = initParams;
       }
  }

 // runCreateReactContextOnNewThread() 方法中内容
final ReactApplicationContext reactApplicationContext =
            createReactContext(initParams.getJsExecutorFactory().create(),
                    initParams.getJsBundleLoader()); // 分析
}

  在 runCreateReactContextOnNewThread() 方法中,我们看到是 ReactInstanceManager.createReactContext() 方法最终创建了 ReactApplicationContext,我们继续看 createReactContext() 方法,有关此方法的2个参数:

  • JSCJavaScriptExecutor jsExecutor:JSCJavaScriptExecutor 继承于JavaScriptExecutor,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用 Native 方法 initHybrid() 初始化 C++ 层 RN 与 JSC 通信的框架
  • JSBundleLoader jsBundleLoader:缓存了 JSBundle 的信息,封装了上层加载 JSBundle 的相关接口,CatalystInstance 通过其间接调用 ReactBridge 去加载 JS 文件,不同的场景会创建不同的加载器,根据 ReactNativeHost 中的配置决定从哪里加载 bundle 文件。

9、createReactContext

private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor,
      JSBundleLoader jsBundleLoader) {
      // ReactApplicationContext 是 reactContext 的包装类
    final ReactApplicationContext reactContext = 
        new ReactApplicationContext(mApplicationContext);

    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
        ? mNativeModuleCallExceptionHandler
        : mDevSupportManager;
    reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
    // 创建 JavaModule 注册表 Builder,用来创建 JavaModule 注册表,
    // JavaModule 注册表将所有的 JavaModule 注册到 CatalystInstance 中。
    NativeModuleRegistry nativeModuleRegistry = 
        processPackages(reactContext, mPackages, false);
    // jsExecutor、nativeModuleRegistry、jsBundleLoader 等各种参数处理好之后,
    // 开始构建 CatalystInstanceImpl 实例。
    CatalystInstanceImpl.Builder catalystInstanceBuilder = 
        new CatalystInstanceImpl.Builder()
      .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
      .setJSExecutor(jsExecutor) // js 执行通信类
      .setRegistry(nativeModuleRegistry) // java 模块注册表
      .setJSBundleLoader(jsBundleLoader) // bundle 加载器
      .setNativeModuleCallExceptionHandler(exceptionHandler); // 异常处理器

    final CatalystInstance catalystInstance;
    try {
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
    }
    if (mJSIModulePackage != null) {
      catalystInstance.addJSIModules(mJSIModulePackage
        .getJSIModules(reactContext, catalystInstance.getJavaScriptContextHolder()));
    }

    if (mBridgeIdleDebugListener != null) {
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    }
    if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
    	// 调用 CatalystInstanceImpl 的 Native 方法把 Java Registry 转换为 Json,
    	// 再由 C++ 层传送到 JS 层。
        catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
    }
    
    // 通过 CatalystInstance 开始加载 JS Bundle
    catalystInstance.runJSBundle(); // 分析

    // 关联 ReacContext 与 CatalystInstance
    reactContext.initializeWithInstance(catalystInstance);
    return reactContext;
  }

  这段代码比较长,它主要做了这几件事:

  • 创建 JavaModule 注册表和 JavaScriptModule 注册表,交给 CatalystInstance 管理。
  • 处理 ReactPackage,将各自的 Module 放入对应的注册表中
  • 通过上面的各个参数创建 CatalystInstance 实例
  • CatalystInstance 关联 ReactContext,开始加载 JS Bundle

  createReactContext 方法中用 catalystInstance.runJSBundle() 来加载 JS bundle。

@Override
  public void runJSBundle() {
    // ...省略代码
    // 调用加载器加载 JS Bundle,不同情况下加载器不同。分析
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
    // ...省略代码
}

  调用栈如下:
CatalystInstanceImpl.runJSBundle() -> JSBundleLoader.loadScript() -> CatalystInstanceImpl.loadScriptFromAssets()/loadScriptFromFile() -> CatalystInstanceImpl.jniLoadScriptFromAssets()/jniLoadScriptFromFile()-> CatalystInstanceImpl::jniLoadScriptFromAssets()/jniLoadScriptFromFile() -> Instance::loadScriptFromString()/loadScriptFromFile()-> NativeToJsBridge::loadApplication() -> JSCExecutor::loadApplicationScript()

  我们假设调用了 loadScriptFromAssets 方法,(本地)可以看出该方法最终调用 Native 方法 jniLoadScriptFromAssets 去加载 JS Bundle

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

10、CatalystInstanceImpl.java

  CatalystInstanceImpl.java 最终还是调用 C++ 层的 CatalystInstanceImpl.cpp 去加载 JS Bundle。 CatalystInstance 是 ReactNative 应用 Java 层、C++ 层、JS 层通信总管理类,总管 Java 层、JS 层核心 Module 映射表与回调,三端通信的入口与桥梁。

public class CatalystInstanceImpl implements CatalystInstance {
private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {

    // Native 方法,用来创建 JNI 相关状态,并返回 mHybridData
    mHybridData = initHybrid();
    // RN 中的三个线程:Native Modules Thread、
    // JS Thread、UI Thread,都是通过 Handler 来管理的。
    mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
        reactQueueConfigurationSpec,
        new NativeExceptionHandler());
    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
    mNativeModuleRegistry = nativeModuleRegistry;
     // 创建 JavaScriptModule 注册表
    mJSModuleRegistry = new JavaScriptModuleRegistry();
    mJSBundleLoader = jsBundleLoader;
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
    mTraceListener = new JSProfilerTraceListener(this);
    
    // 在 C++ 层初始化通信桥 Bridge。
    initializeBridge(
      new BridgeCallback(this),
      jsExecutor,
      mReactQueueConfiguration.getJSQueueThread(),
      mNativeModulesQueueThread,
      mNativeModuleRegistry.getJavaModules(this),
      mNativeModuleRegistry.getCxxModules());

    mJavaScriptContextHolder = 
        new JavaScriptContextHolder(getJavaScriptContext());
  }

 // 在 C++ 层初始化通信桥 ReactBridge
 private native void initializeBridge(
      ReactCallback callback,
      JavaScriptExecutor jsExecutor,
      MessageQueueThread jsQueue,
      MessageQueueThread moduleQueue,
      Collection<JavaModuleWrapper> javaModules,
      Collection<ModuleHolder> cxxModules);
}

  从 CatalystInstanceImpl 的构建过程可以看出,CatalystInstanceImpl 是个封装管理类,封装了各种注册表,以及初始化 JNI。

11、CatalystInstanceImpl.cpp

  在项目的 node_modules/react-native/ReactAndroid/src/main/jni/react/jni 可以找到 CatalystInstanceImpl.cpp。

void CatalystInstanceImpl::jniLoadScriptFromAssets(
    jni::alias_ref<JAssetManager::javaobject> assetManager,
    const std::string& assetURL,
    bool loadSynchronously) {
  const int kAssetsLength = 9; // strlen("assets://");
  // 获取 source js Bundle 的路径名
  auto sourceURL = assetURL.substr(kAssetsLength);
  // assetManager 是 Java 层传递过来的 AssetManager,
  // 调用 JSLoader.cpp 里的 extractAssetManager() 方法,
  // extractAssetManager() 再调用 android/asset_manager_jni.h
  // 里的 AssetManager_fromJava() 方法获取 AssetManager 对象。
  auto manager = extractAssetManager(assetManager);
  // 调用 JSloader.cpp 的 loadScriptFromAssets 方法,
  // 读取 js Bundle 里面的内容
  auto script = loadScriptFromAssets(manager, sourceURL);
  // unbundle 命令打包判断,build.gradle 默认是 bundle 打包方式。
  if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
    auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
    auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
    instance_->loadRAMBundle(
      std::move(registry),
      std::move(script),
      sourceURL,
      loadSynchronously);
    return;
  } else if (Instance::isIndexedRAMBundle(&script)) {
    instance_->loadRAMBundleFromString(std::move(script), sourceURL);
  } else {
    // bundle 命令打包走此流程,instance_ 是 Instance.h 中类的实例
    instance_->
        loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
  }
}

  关于 unbundle 命令
  unbundle 命令,使用方式和 bundle 命令完全相同。unbundle 命令是在 bundle 命令的基础上增加了一项功能,除了生成整合 JS 文件 index.android.bundle 外,还会生成各个单独的未整合 JS 文件(但会被优化),全部放在 js-modules 目录下,同时会生成一个名为 UNBUNDLE 的标识文件,一并放在其中。UNBUNDLE 标识文件的前4个字节固定为 0xFB0BD1E5,用于加载前的校验。

  接着会调用 Instance.cpploadScriptFromString() 方法去解析 JS Bundle 里的内容。

void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,
                                    std::string sourceURL,
                                    bool loadSynchronously) {
  if (loadSynchronously) {
    loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));
  } else {
    loadApplication(nullptr, std::move(string), std::move(sourceURL)); // 分析
  }
}

void Instance::loadApplicationSync(
    std::unique_ptr<JSModulesUnbundle> unbundle,
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL) {
  std::unique_lock<std::mutex> lock(m_syncMutex);
  m_syncCV.wait(lock, [this] { return m_syncReady; });

  // nativeToJsBridge_ 也是在 Instance::initializeBridget() 方法里初始化的
  // ,具体实现在 NativeToJsBridge.cpp 里。 
  nativeToJsBridge_->loadApplicationSync(std::move(unbundle), 
      std::move(string), std::move(sourceURL));
}

12、NativeToJsBridge.cpp

  在项目node_modules/react-native/ReactCommon 的 cxxReact 的 NativeToJsBridge.cpp 文件。最终由 C++ 中的 JSCExecutor.cpp 完成了 JS Bundle 的加载,核心逻辑都在 JSCExecutor.cpp 中。

void NativeToJsBridge::loadApplication(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {
    
    // 获取一个 MessageQueueThread,然后在线程中执行一个 Task。
  runOnExecutorQueue(
      [this,
       bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)),
       startupScript=folly::makeMoveWrapper(std::move(startupScript)),
       startupScriptSourceURL=std::move(startupScriptSourceURL)]
        (JSExecutor* executor) mutable {
        
    auto bundleRegistry = bundleRegistryWrap.move();
    if (bundleRegistry) {
      executor->setBundleRegistry(std::move(bundleRegistry));
    }
    try {
      // executor 也与 Java 中的 JSCJavaScriptExecutor 对应。
      // 它的实例在 JSIExecutor.cpp 中实现。
      executor->loadApplicationScript(std::move(*startupScript),
                                      std::move(startupScriptSourceURL)); // 分析
    } catch (...) {
      m_applicationScriptHasFailure = true;
      throw;
    }
  });
}

13、JSCExecutor.cpp

void JSCExecutor::loadApplicationScript(
    std::unique_ptr<const JSBigString> script,
    std::string sourceURL) {
    SystraceSection s("JSIExecutor::loadApplicationScript");
    //...//
    // 解释执行 JS
    runtime_->evaluateJavaScript(
      std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
    flush(); // 分析
   //...//
}
void JSCExecutor::flush() {
	  ...
	  // 绑定 bridge,核心就是通过 getGlobalObject() 将 JS 与 C++
      // 通过 Webkit jSC 实现绑定
	  bindBridge();
	  // 返回给 callNativeModules
      callNativeModules(m_flushedQueueJS->callAsFunction({}));
	  ...
}
void JSCExecutor::callNativeModules(Value&& value) {
	...
	// 把 JS 层相关通信数据转换为 JSON 格式
	auto calls = value.toJSONString();
	// m_delegate 为 JsToNativeBridge 对象。
    m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
	...
}

14、ReactInstanceManager

  flushedQueueJS 执行的是 MessageQueue.js 的 flushedQueue() 方法,此时 JS 已被加载到队列中等待 Java 层来驱动它。加载完 JS 后,返回 reactApplicationContext,继续跟进它的实现。

@ThreadConfined(UI)
  private void runCreateReactContextOnNewThread(
       final ReactContextInitParams initParams) {
    mCreateReactContextThread =
        new Thread(
            null,
            new Runnable() {
              @Override
              public void run() {
              	// 省略部分代码
                try {
                  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);
                          }
                        }
                      };
                  reactApplicationContext.runOnNativeModulesQueueThread(
                     setupReactContextRunnable);
                } catch (Exception e) {
                  mDevSupportManager.handleException(e);
                }
              }
            },
            "create_react_context");
  }

  回到 ReactInstanceManager 类的 runCreateReactContextOnNewThread() 方法中,看到 setupReactContext() 方法,这就是加载 JS Bundle 之后执行的代码

private void setupReactContext(final ReactApplicationContext reactContext) {
    synchronized (mAttachedReactRoots) {

      CatalystInstance catalystInstance =
          Assertions.assertNotNull(reactContext.getCatalystInstance());
       // Native Java module 的初始化
      catalystInstance.initialize();
      mDevSupportManager.onNewReactContextCreated(reactContext);
      mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
      // 复位生命周期
      moveReactContextToCurrentLifecycleState();
      // 遍历 ReactRootView
      for (ReactRoot reactRoot : mAttachedReactRoots) {
        // 遍历 ReactRootView  分析
        attachRootViewToInstance(reactRoot); // 分析
      }
    }
    //...省略//
  }

  可以看到 attachRootViewToInstance(ReactRootView) 方法,进入后:

private void attachRootViewToInstance(final ReactRootView rootView) {
    UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, rootView.getUIManagerType());

    @Nullable Bundle initialProperties = rootView.getAppProperties();
    // 将 ReactRootView 作为根布局
    final int rootTag = uiManagerModule.addRootView(
      rootView,
      initialProperties == null ?
            new WritableNativeMap() : Arguments.fromBundle(initialProperties),
        rootView.getInitialUITemplate());
    rootView.setRootViewTag(rootTag);
    // 启动流程的入口 分析
    rootView.runApplication();
    // 省略部分代码
    UiThreadUtil.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        rootView.onAttachedToReactInstance();
      }
    });
  }
@Override
  public void runApplication() {
      try {
        if (mReactInstanceManager == null || !mIsAttachedToInstance) {
          return;
        }

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

        CatalystInstance catalystInstance = reactContext.getCatalystInstance();
        WritableNativeMap appParams = new WritableNativeMap();
        appParams.putDouble("rootTag", getRootViewTag());
        @Nullable Bundle appProperties = getAppProperties();
        if (appProperties != null) {
          appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
        }
        if (getUIManagerType() == FABRIC) {
          appParams.putBoolean("fabric", true);
        }

        mShouldLogContentAppeared = true;

        String jsAppModuleName = getJSModuleName();
        // 分析
        catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
      } finally {
        Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      }
  }

15、AppRegistry.js

  catalystInstance.getJSModule(AppRegistry.class)
  AppRegistry.class 是 JS 层暴露给 Java 层的接口方法,它的真正实现在 AppRegistry.js 里,AppRegistry.js 是运行所有 RN 应用的 JS 层入口。

/**
 - JS module interface - main entry point for launching React application for a given key.
 */
 // AppRegistry.java
public interface AppRegistry extends JavaScriptModule {
  void runApplication(String appKey, WritableMap appParameters);
  void unmountApplicationComponentAtRootTag(int rootNodeTag);
  void startHeadlessTask(int taskId, String taskKey, WritableMap data);
}

  上面代码最终调用的 AppRegistry.js 中的这个函数

/**
 - Loads the JavaScript bundle and runs the app.
 -  4. See http://facebook.github.io/react-native/docs/appregistry.html#runapplication
   */
  runApplication(appKey: string, appParameters: any): void {
    const msg =
      'Running application "' +
      appKey +
      '" with appParams: ' +
      JSON.stringify(appParameters) +
      '. ' +
      '__DEV__ === ' +
      String(__DEV__) +
      ', development-level warning are ' +
      (__DEV__ ? 'ON' : 'OFF') +
      ', performance optimizations are ' +
      (__DEV__ ? 'OFF' : 'ON');
    infoLog(msg);
    BugReporting.addSource(
      'AppRegistry.runApplication' + runCount++,
      () => msg,
    );
    invariant(
      runnables[appKey] && runnables[appKey].run,
      'Application ' +
        appKey +
        ' has not been registered.\n\n' +
        "Hint: This error often happens when you're running the packager " +
        '(local dev server) from a wrong folder. For example you have ' +
        'multiple apps and the packager is still running for the app you ' +
        'were working on before.\nIf this is the case, simply kill the old ' +
        'packager instance (e.g. close the packager terminal window) ' +
        'and start the packager in the correct app folder (e.g. cd into app ' +
        "folder and run 'npm start').\n\n" +
        'This error can also happen due to a require() error during ' +
        'initialization or failure to call AppRegistry.registerComponent.\n\n',
    );

    SceneTracker.setActiveScene({name: appKey});
    runnables[appKey].run(appParameters);
  },

  基本到这,就会去调用 JS 进行组件渲染,再通过 Java 层的 UIManagerModule 将 JS 组件转换为 Android 组件,最终显示在 ReactRootView 上,即完成启动过程。

简单总结

  启动流程可分以下几步:

  • 在程序启动的时候,也就是 ReactActivity 的 onCreate() 函数中,我们会去创建一个 ReactInstanceManager 对象,ReactInstanceManager 用于管理生命周期,管理 ReactRootView,以及一些配置等。
  • ReactRootView 作为应用的根视图,通过调用 startReactApplication() 方法启动应用。
  • RN 应用页面渲染前,需要先创建上下文 ReactContext, 它的创建流程在异步任务 ReactContextInitAsyncTask 负责来完成这个任务。
  • ReactContextInitAsyncTask 在后台 ReactContextInitAsyncTask.doInBackground() 执行 ReactContext 的创建,创建 ReactContext 的过程中,会依据 ReactPackage 创建 JavaScriptModuleRegistry 与 NativeModuleRegistry 注册表以及它们的管理类 CatalystInstanceImpl,同时创建 JS、Native 与 UI 线程队列,并最终调用 CatalystInstanceImpl.runJSBundle() 去异步加载 JS Bundle 文件**(C++层)**
  • 后台任务执行完成后,在 ReactContextInitAsyncTask.onPostExecute() 会调用 ReactInstanceManager.setupReactContext() 设置创建好的 ReactContext,并将 ReactRootView 加载进来,并调用 RN 应用的 JS 入口 APPRegistry 来启动应用。
  • JS 层找到已经注册的对应的启动组件,执行 renderApplication() 来渲染整个应用。

------至所有正在努力奋斗的程序猿们!加油!!
有码走遍天下 无码寸步难行
1024 - 梦想,永不止步!
爱编程 不爱Bug
爱加班 不爱黑眼圈
固执 但不偏执
疯狂 但不疯癫
生活里的菜鸟
工作中的大神
身怀宝藏,一心憧憬星辰大海
追求极致,目标始于高山之巅
一群怀揣好奇,梦想改变世界的孩子
一群追日逐浪,正在改变世界的极客
你们用最美的语言,诠释着科技的力量
你们用极速的创新,引领着时代的变迁

——乐于分享,共同进步,欢迎补充
——Treat Warnings As Errors
——Any comments greatly appreciated
——Talking is cheap, show me the code
——诚心欢迎各位交流讨论!QQ:1138517609
——CSDN:https://blog.csdn.net/u011489043
——简书:https://www.jianshu.com/u/4968682d58d1
——GitHub:https://github.com/selfconzrr

发布了79 篇原创文章 · 获赞 207 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/u011489043/article/details/104407301