React Native新架构之Android端初始化源码分析

React Native新架构之Android端初始化源码分析

前言

注意,本文是基于React Native 0.83版本源码进行分析。文章基本属于保姆式分析,有详细的衔接流程,本专栏让你彻底理解新架构是怎么回事。

初始化流程

Application

根据Android原生初始化的顺序,我们应先从应用的Application开始。这里我们就打开工程源码提供的helloworld示例作为研究的开始:

源码react-native/private/helloworld/android/app/src/main/java/com/helloworld/MainApplication.kt

kotlin 复制代码
class MainApplication : Application(), ReactApplication {

  override val reactHost: ReactHost by
      lazy(LazyThreadSafetyMode.NONE) {
        getDefaultReactHost(
            context = applicationContext,
            packageList =
                PackageList(this).packages.apply {
                  // 例如,目前还无法自动链接的软件包可以手动添加到这里:
                  // add(MyReactNativePackage())
                },
        )
      }

  override fun onCreate() {
    super.onCreate()
    loadReactNative(this)
  }
}

一个ReactNative的Android原生工程,要求我们必须自定义一个派生自Application且实现了ReactApplication接口的子类。这里逻辑十分简单,我们先看一下ReactApplication接口有什么要求:

kotlin 复制代码
/** 表示 React Native 应用程序实例的接口 */
public interface ReactApplication {
  /** Get the default [ReactNativeHost] for this app. */
  @Suppress("DEPRECATION")
  @Deprecated(
      "You should not use ReactNativeHost directly in the New Architecture. Use ReactHost instead.",
      ReplaceWith("reactHost"),
  )
  public val reactNativeHost: ReactNativeHost
    get() {
      throw RuntimeException("You should not use ReactNativeHost directly in the New Architecture")
    }

  /**
   * 获取此应用的默认的[ReactHost]。此方法将由 React Native 的新架构使用。
   */
  public val reactHost: ReactHost?
    get() = null
}

这里reactNativeHost是已经过时的旧架构需要的,我们主要研究新架构,忽略。也就是说ReactApplication接口的功能非常简单,只是需要实现类提供一个返回ReactHost实例的getter

现在我们再来看MainApplication,其实非常简单,只做了两件事:

  1. 实现了一个返回ReactHost实例的懒加载getter
  2. onCreate调用loadReactNative

这里getDefaultReactHost是一个静态方法,源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt

kotlin 复制代码
/**
 * 一个实用工具类,可简化开源新应用 [ReactHost] 的配置。
 *
 * [ReactHost] 是一个接口,负责处理 React Native 应用在无桥模式下的生命周期。
 */
public object DefaultReactHost {
  private var reactHost: ReactHost? = null

  /**
   * 用于创建应用程序默认的 [ReactHost] 的实用函数。此方法由"New App"模板使用。  
   *
   * @param context 用于创建 [ReactHost] 的 Android [Context]
   * @param packageList 用于创建 [ReactHost] 的 [ReactPackage] 列表
   * @param jsMainModulePath Metro 平台上应用程序主模块的路径。通常为 `index` or `index.<platform>`
   * @param jsBundleAssetPath 相对于 assets 目录的 JS 包路径. 
   *   将以 `asset://...` URL 的形式呈现。通常为 `index.android.bundle`
   *
   * @param jsBundleFilePath 文件系统中 JS 包的路径. 
   *   将以 `file://...` URL 的形式呈现
   *
   * @param jsRuntimeFactory 用于执行 [ReactHost] 的 JS 引擎,默认为 Hermes
   * @param useDevSupport 是否启用开发支持,默认为 ReactBuildConfig.DEBUG.
   * @param cxxReactPackageProviders cxxreactpackage提供程序列表(用于注册 C++ Turbo 模块)
   * @param exceptionHandler 宿主应用程序可用于响应 React Native 内部抛出的异常的回调函数
   * @param bindingsInstaller 可用于安装绑定
   *
   * TODO(T186951312): Should this be @UnstableReactNativeAPI?
   */
  @OptIn(UnstableReactNativeAPI::class)
  @JvmStatic
  public fun getDefaultReactHost(
      context: Context,
      packageList: List<ReactPackage>,
      jsMainModulePath: String = "index",
      jsBundleAssetPath: String = "index.android.bundle",
      jsBundleFilePath: String? = null,
      jsRuntimeFactory: JSRuntimeFactory? = null,
      useDevSupport: Boolean = ReactBuildConfig.DEBUG,
      cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
      exceptionHandler: (Exception) -> Unit = { throw it },
      bindingsInstaller: BindingsInstaller? = null,
  ): ReactHost {
    if (reactHost == null) {

      val bundleLoader =
          if (jsBundleFilePath != null) {
            if (jsBundleFilePath.startsWith("assets://")) {
              JSBundleLoader.createAssetLoader(context, jsBundleFilePath, true)
            } else {
              JSBundleLoader.createFileLoader(jsBundleFilePath)
            }
          } else {
            JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true)
          }
      val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()
      cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) }
      val defaultReactHostDelegate =
          DefaultReactHostDelegate(
              jsMainModulePath = jsMainModulePath,
              jsBundleLoader = bundleLoader,
              reactPackages = packageList,
              jsRuntimeFactory = jsRuntimeFactory ?: HermesInstance(),
              bindingsInstaller = bindingsInstaller,
              turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder,
              exceptionHandler = exceptionHandler,
          )
      val componentFactory = ComponentFactory()
      DefaultComponentsRegistry.register(componentFactory)
      // TODO: T164788699 寻找访问 ReactHostImpl 以初始化 ReactHost 的替代方法
      reactHost =
          ReactHostImpl(
              context,
              defaultReactHostDelegate,
              componentFactory,
              true /* allowPackagerServerAccess */,
              useDevSupport,
          )
    }
    return reactHost as ReactHost
  }

  /**
   * 用于 Brownfield 场景的清理函数,在销毁 React Native 实例后清除 ReactHost 的单例引用
   */
  internal fun invalidate() {
    reactHost = null
  }
}

这里reactHost是一个静态单例引用,因此释放时需要调用invalidate方法。Brownfield 场景是指在现有应用中集成新技术,那么这里就是指原生 Android 应用中嵌入 RN 页面。

我们再来看loadReactNative方法,它的源码并不在工程中,而是在构建时自动生成,我们找到其代码模版react-native/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateEntryPointTask.kt

kotlin 复制代码
companion object {
    const val GENERATED_FILENAME = "com/facebook/react/ReactNativeApplicationEntryPoint.java"

    // language=java
    val generatedFileContentsTemplate =
        """
        package com.facebook.react;

        import android.app.Application;
        import android.content.Context;
        import android.content.res.Resources;

        import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
        import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
        import com.facebook.react.views.view.WindowUtilKt;
        import com.facebook.react.soloader.OpenSourceMergedSoMapping;
        import com.facebook.soloader.SoLoader;

        import java.io.IOException;

        /**
          * This class is the entry point for loading React Native using the configuration
          * that the users specifies in their .gradle files.
          *
          * The `loadReactNative(this)` method invocation should be called inside the
          * application onCreate otherwise the app won't load correctly.            
          */
        public class ReactNativeApplicationEntryPoint {
          public static void loadReactNative(Context context) {
            try {
               SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);
            } catch (IOException error) {
              throw new RuntimeException(error);
            }

            if ({{packageName}}.BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
              DefaultNewArchitectureEntryPoint.load();
            }

            if ({{packageName}}.BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {
              WindowUtilKt.setEdgeToEdgeFeatureFlagOn();
            }
          }
        }
        """
            .trimIndent()
  }

可以看到ReactNativeApplicationEntryPoint是加载 React Native 的入口点,它加载了一些用户在 .gradle文件中指定的配置。而loadReactNative(this) 方法必须在应用程序的 onCreate 方法中调用,否则应用程序将无法正确加载。其实此方法主要就是初始化了SoLoaderSoLoader是Facebook开源的一个工具库,主要用于安卓的动态库加载管理。后面再单独分析此库的源码。

小结

Application中主要做两件事:

  1. 调用loadReactNative
  2. 提供一个创建ReactHost实例的getter

MainActivity

接下来我们来看react-native/private/helloworld/android/app/src/main/java/com/helloworld/MainActivity.kt

kotlin 复制代码
class MainActivity : ReactActivity() {

  /**
   * 返回从 JavaScript 注册的主组件的名称。此名称用于安排组件的渲染。
   */
  override fun getMainComponentName(): String = "HelloWorld"

  /**
   * 返回 [ReactActivityDelegate] 的实例。使用 [DefaultReactActivityDelegate],它允许您使用单个布尔标志 [fabricEnabled] 启用新架构。
   */
  override fun createReactActivityDelegate(): ReactActivityDelegate =
      DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}

这里主要是实现了ReactActivity中的两个方法,详细逻辑查看react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java,这是一个Java类:

java 复制代码
/** React Native 应用的基础Activity */
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);
    if (AndroidVersion.isAtLeastTargetSdk36(this)) {
      getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback);
    }
  }

  @Override
  protected void onPause() {
    super.onPause();
    mDelegate.onPause();
  }

  @Override
  protected void onResume() {
    super.onResume();
    mDelegate.onResume();
  }

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

  public @Nullable ReactDelegate getReactDelegate() {
    return mDelegate.getReactDelegate();
  }

  public ReactActivityDelegate getReactActivityDelegate() {
    return mDelegate;
  }

  // ......

  protected ReactHost getReactHost() {
    return mDelegate.getReactHost();
  }

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

可以看到,ReactActivity中主要是将一些回调代理给ReactActivityDelegate类,创建该类的createReactActivityDelegate方法可以由子类实现。这里正是在MainActivity中创建了ReactActivityDelegate实例。

接下来查看react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt

kotlin 复制代码
/**
 * 一个实用工具类,可简化开源应用中 [ReactActivityDelegate] 的设置
 * 具体来说,使用此类,您可以通过构造函数中的布尔标志轻松控制是否为 Activity 启用 Fabric
 *
 * @param fabricEnabled 是否应为此 Activity 的 RootView 启用 Fabric
 */
public open class DefaultReactActivityDelegate(
    activity: ReactActivity,
    mainComponentName: String,
    private val fabricEnabled: Boolean = false,
) : ReactActivityDelegate(activity, mainComponentName) {

  @Deprecated(
      message =
          "Creating DefaultReactActivityDelegate with both fabricEnabled and " +
              "concurrentReactEnabled is deprecated. Please pass only one boolean value that will" +
              " be used for both flags",
      level = DeprecationLevel.WARNING,
      replaceWith =
          ReplaceWith("DefaultReactActivityDelegate(activity, mainComponentName, fabricEnabled)"),
  )
  public constructor(
      activity: ReactActivity,
      mainComponentName: String,
      fabricEnabled: Boolean,
      @Suppress("UNUSED_PARAMETER") concurrentReactEnabled: Boolean,
  ) : this(activity, mainComponentName, fabricEnabled)

  override fun isFabricEnabled(): Boolean = fabricEnabled
}

该类并没是有那些代理方法的实现,因此继续研究父类react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java

小结

MainActivity 中主要做一件事,重写createReactActivityDelegate方法创建ReactActivityDelegate实例。

ReactActivityDelegate

java 复制代码
/**
 * {@link ReactActivity} 的代理类。您可以继承此类以提供自定义实现
 * 例如,如果您的 Application 类没有实现 {@link ReactApplication},则可以调用 {@link #getReactNativeHost()}
 */
@Nullsafe(Nullsafe.Mode.LOCAL)
public class ReactActivityDelegate {

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

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

  /**
   * 尽量使用 ReactActivity,因为它默认会调用所有 Activity 生命周期方法。
   * 它还实现了 ReactDelegate 所需的 DefaultHardwareBackBtnHandler 接口。
   */
  @Deprecated
  public ReactActivityDelegate(@Nullable Activity activity, @Nullable String mainComponentName) {
    mActivity = activity;
    mMainComponentName = mainComponentName;
  }

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

  /**
   * 用于填充启动选项的公共 API,这些选项将作为"initialProperties"传递给渲染器。
   *
   * @return 返回 null 或键值对映射(以 Bundle 形式)
   */
  protected @Nullable Bundle getLaunchOptions() {
    return null;
  }

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

  /**
   * 获取启用 Bridgeless 后此应用使用的 {@link ReactHost}
   * 默认情况下,此方法假定 {@link Activity#getApplication()} 是 {@link ReactApplication} 的实例,
   * 并调用 {@link ReactApplication#getReactHost()}。
   * 如果您的应用类未实现 {@code ReactApplication} 接口,
   * 或者您使用其他机制存储 {@code ReactHost}(例如,将其作为静态字段存储),请重写此方法。
   */
  public @Nullable ReactHost getReactHost() {
    return ((ReactApplication) getPlainActivity().getApplication()).getReactHost();
  }

  protected @Nullable ReactDelegate getReactDelegate() {
    return mReactDelegate;
  }

  @Nullable
  public String getMainComponentName() {
    return mMainComponentName;
  }

  public void onCreate(@Nullable Bundle savedInstanceState) {
    Systrace.traceSection(
        Systrace.TRACE_TAG_REACT,
        "ReactActivityDelegate.onCreate::init",
        () -> {
          String mainComponentName = getMainComponentName();
          final Bundle launchOptions = composeLaunchOptions();
          if (mActivity != null) {
            Window window = mActivity.getWindow();
            if (window != null) {
              if (WindowUtilKt.isEdgeToEdgeFeatureFlagOn()) {
                WindowUtilKt.enableEdgeToEdge(window);
              }
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled()) {
                window.setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
              }
            }
          }
          if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
            mReactDelegate =
                new ReactDelegate(
                    getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
          } else {
            // 省略......
          }
          if (mainComponentName != null) {
            loadApp(mainComponentName);
          }
        });
  }

  protected void loadApp(@Nullable String appKey) {
    Objects.requireNonNull(mReactDelegate).loadApp(Objects.requireNonNull(appKey));
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  }

  public void setReactSurface(ReactSurface reactSurface) {
    Objects.requireNonNull(mReactDelegate).setReactSurface(reactSurface);
  }

  public void setReactRootView(ReactRootView reactRootView) {
    Objects.requireNonNull(mReactDelegate).setReactRootView(reactRootView);
  }

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

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

  protected ReactActivity getReactActivity() {
    return ((ReactActivity) getContext());
  }

  /**
   * 从 ReactHost 或 ReactInstanceManager 获取当前的 {@link ReactContext}
   *
   * <p>不要存储对此的引用,如果 React 实例重新加载或销毁,此上下文将不再有效。</p>
   */
  public @Nullable ReactContext getCurrentReactContext() {
    return Objects.requireNonNull(mReactDelegate).getCurrentReactContext();
  }

  // 省略部分方法......
}

可以看到,在onCreate方法的实现中,新架构的核心逻辑就是创建了ReactDelegate实例对象,并调用了loadApp方法。

loadApp主要做了两件事,首先调用ReactDelegate类的loadApp方法,继续跟踪源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.kt

kotlin 复制代码
  /**
   * 为指定的appKey启动 React Surface
   *
   * @param appKey 要加载到 Surface 中的应用app ID
   */
  public fun loadApp(appKey: String) {
    // 启用 Bridgeless 功能后,创建并启动surface
    if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
      val reactHost = reactHost
      if (reactSurface == null && reactHost != null) {
        reactSurface = reactHost.createSurface(activity, appKey, launchOptions)
      }
      reactSurface?.start()
    } else {
      // 省略旧架构......
    }
  }

这里新架构的核心逻辑是创建ReactSurface对象并调用start方法。我们后面再研究ReactSurface源码,先看一下ReactActivityDelegateloadApp做的第二件事,就是设置Activity的ContentView:getPlainActivity().setContentView(mReactDelegate.getReactRootView())

kotlin 复制代码
// ReactDelegate.kt

public var reactRootView: ReactRootView?
    get() {
      return if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
        if (reactSurface != null) {
          reactSurface?.view as ReactRootView?
        } else {
          null
        }
      } else {
        internalReactRootView
      }
    }
    set(reactRootView) {
      internalReactRootView = reactRootView
    }

可以看到,新架构实际上就是返回了reactSurface中的view作为ReactRootView。现在调用流程都指向了ReactSurface,继续查看reactHost.createSurface方法的实现来找到ReactSurface的具体实现类,可以看到实现类是ReactSurfaceImpl

kotlin 复制代码
  override fun createSurface(
      context: Context,
      moduleName: String,
      initialProps: Bundle?,
  ): ReactSurface {
    val surface = ReactSurfaceImpl(context, moduleName, initialProps)
    val surfaceView = ReactSurfaceView(context, surface)
    surfaceView.setShouldLogContentAppeared(true)
    surface.attachView(surfaceView)
    surface.attach(this)
    return surface
  }
小结

ReactActivityDelegate 中主要做了两件事:

  1. 调用ReactDelegateloadApp方法

  2. 设置ActivityContentView

ReactHostImpl

继续跟踪react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceImpl.kt

kotlin 复制代码
  override fun start(): TaskInterface<Void> {
    if (surfaceViewRef.get() == null) {
      return Task.forError(
          IllegalStateException("Trying to call ReactSurface.start(), but view is not created.")
      )
    }

    val host =
        reactHost
            ?: return Task.forError(
                IllegalStateException(
                    "Trying to call ReactSurface.start(), but no ReactHost is attached."
                )
            )
    return host.startSurface(this)
  }

实际实现是调用了reactHoststartSurface方法,并将当前ReactSurfaceImpl实例作为参数传入:

kotlin 复制代码
// ReactHostImpl.kt

/**
 * 开始在屏幕上渲染 React Native Surface
 *
 * @param surface 要渲染的 ReactSurface
 * @return A Task that will complete when startSurface has been called.
 */
internal fun startSurface(surface: ReactSurfaceImpl): TaskInterface<Void> {
  val method = "startSurface(surfaceId = ${surface.surfaceID})"
  stateTracker.enterState(method, "Schedule")

  attachSurface(surface)
  return callAfterGetOrCreateReactInstance(method, bgExecutor) { reactInstance: ReactInstance ->
    stateTracker.enterState(method, "Execute")
    reactInstance.startSurface(surface)
  }
}

可以看到,首先调用attachSurface方法将ReactSurfaceImpl实例添加到了attachedSurfaces中保存,这里attachedSurfaces是一个HashSet。接下来调用了callAfterGetOrCreateReactInstance方法,并传入了一个闭包,在这个闭包实现中又调用了reactInstance.startSurface(surface)

callAfterGetOrCreateReactInstance方法返回了一个TaskInterface类型,这里 TaskInterface类似于JavaScript 的 Promise,查看bgExecutor的构建private val bgExecutor: Executor = Executors.newSingleThreadExecutor(),这里是有一个单独的后台线程,可见此处是进行了异步调用。继续查看callAfterGetOrCreateReactInstance方法实现:

kotlin 复制代码
  /** 如果 ReactInstance 尚不存在,则创建一个,并对其执行操作 */
  private fun callAfterGetOrCreateReactInstance(
      callingMethod: String,
      executor: Executor = Task.IMMEDIATE_EXECUTOR,
      runnable: (reactInstance: ReactInstance) -> Unit,
  ): Task<Void> =
      getOrCreateReactInstance()
          .onSuccess<Void>(
              { task ->
                val reactInstance = task.getResult()
                if (reactInstance == null) {
                  raiseSoftException(
                      "callAfterGetOrCreateReactInstance($callingMethod)",
                      "Execute: reactInstance is null. Dropping work.",
                  )
                } else {
                  runnable(reactInstance)
                }
                null
              },
              executor,
          )

接下来getOrCreateReactInstance的实现存在一系列方法调用:

kotlin 复制代码
/**
   * 创建 ReactInstance 的入口点
   *
   * 如果 ReactInstance 正在重新加载,则会返回 reload 任务。
   * 如果 ReactInstance 正在销毁,则会等待销毁完成后再进行创建。
   */
  private fun getOrCreateReactInstance(): Task<ReactInstance> =
      Task.call({ waitThenCallGetOrCreateReactInstanceTask() }, bgExecutor)

  @ThreadConfined("ReactHost")
  private fun waitThenCallGetOrCreateReactInstanceTask(): Task<ReactInstance> =
      waitThenCallGetOrCreateReactInstanceTaskWithRetries(0, 4)

  @ThreadConfined("ReactHost")
  private fun waitThenCallGetOrCreateReactInstanceTaskWithRetries(
      tryNum: Int,
      maxTries: Int,
  ): Task<ReactInstance> {
    val method = "waitThenCallGetOrCreateReactInstanceTaskWithRetries"
    // 如果正在 Reload,返回 reload task
    reloadTask?.let { task ->
      stateTracker.enterState(method, "React Native is reloading. Return reload task.")
      return task
    }

    // 如果正在 Destroy,等待完成后重试
    destroyTask?.let { task ->
      val shouldTryAgain = tryNum < maxTries
      if (shouldTryAgain) {
        stateTracker.enterState(
            method,
            "React Native is tearing down.Wait for teardown to finish, before trying again (try count = $tryNum).",
        )
        // 等待 destroy 完成,然后递归重试
        return task.onSuccessTask(
            { waitThenCallGetOrCreateReactInstanceTaskWithRetries(tryNum + 1, maxTries) },
            bgExecutor,
        )
      }

      // 达到最大重试次数,记录异常
      raiseSoftException(
          method,
          "React Native is tearing down. Not wait for teardown to finish: reached max retries.",
      )
    }

    // 没有阻塞,创建
    return getOrCreateReactInstanceTask()
  }

继续查看getOrCreateReactInstanceTask方法

kotlin 复制代码
  @ThreadConfined("ReactHost")
  private fun getOrCreateReactInstanceTask(): Task<ReactInstance> {
    val method = "getOrCreateReactInstanceTask()"
    stateTracker.enterState(method)

    // 使用 BridgelessAtomicRef 确保只创建一次
    return createReactInstanceTaskRef.getOrCreate {
      stateTracker.enterState(method, "Start")
      // 确保 ReactHost 没有被 invalidate
      Assertions.assertCondition(
          !hostInvalidated,
          "Cannot start a new ReactInstance on an invalidated ReactHost",
      )

      ReactMarker.logMarker(
          ReactMarkerConstants.REACT_BRIDGELESS_LOADING_START,
          BRIDGELESS_MARKER_INSTANCE_KEY,
      )

      val creationTask =
          jsBundleLoader.onSuccess(
              { task ->
                val bundleLoader = checkNotNull(task.getResult())
                // 创建或获取 ReactContext
                val reactContext =
                    bridgelessReactContextRef.getOrCreate {
                      stateTracker.enterState(method, "Creating BridgelessReactContext")
                      BridgelessReactContext(context, this)
                    }
                reactContext.jsExceptionHandler = devSupportManager

                // 创建 ReactInstance
                stateTracker.enterState(method, "Creating ReactInstance")
                val instance =
                    ReactInstance(
                        reactContext,
                        reactHostDelegate,
                        componentFactory,
                        devSupportManager,
                        { e: Exception -> this.handleHostException(e) },
                        useDevSupport,
                        getOrCreateReactHostInspectorTarget(),
                    )
                reactInstance = instance

                // 设置内存压力监听
                val memoryPressureListener = createMemoryPressureListener(instance)
                this.memoryPressureListener = memoryPressureListener
                memoryPressureRouter.addMemoryPressureListener(memoryPressureListener)

                // 在 JS Bundle 执行的同时,并行地预先初始化 TurboModules
                                // 因为 TurboModuleManager 会处理任何并发访问
                instance.initializeEagerTurboModules()

                // 加载 JS Bundle
                stateTracker.enterState(method, "Loading JS Bundle")
                instance.loadJSBundle(bundleLoader)

                stateTracker.enterState(
                    method,
                    "DevSupportManager.onNewReactContextCreated()",
                )
                devSupportManager.onNewReactContextCreated(reactContext)

                reactContext.runOnJSQueueThread {
                  // 在 JS 线程上执行,以确保 JS 包已加载完毕。
                  // TODO T76081936 Move this if we switch to a sync RTE
                  ReactMarker.logMarker(
                      ReactMarkerConstants.REACT_BRIDGELESS_LOADING_END,
                      BRIDGELESS_MARKER_INSTANCE_KEY,
                  )
                }

                // 返回创建结果
                CreationResult(instance, reactContext, reloadTask != null)
              },
              bgExecutor,
          )

      // 生命周期更新(在 UI 线程)
      val lifecycleUpdateTask = task@{ task: Task<CreationResult> ->
        if (task.isFaulted()) {
          // handleHostException 可能会抛出异常,因此请将其移到任务调度程序之外。
          uiExecutor.execute { handleHostException(checkNotNull(task.getError())) }
          return@task
        }

        val result = checkNotNull(task.getResult())
        val reactContext = result.context
        val isReloading = result.isReloading
        val isManagerResumed = reactLifecycleStateManager.lifecycleState == LifecycleState.RESUMED

        /**
         * ReactContext.onHostResume() 应该只在用户导航到第一个 React Native 页面时被调用。
         *
         * 初始化阶段:当用户导航到 React Native 页面时,应用程序会将 React 管理器置于 resumed 状态。
         * 有两种初始化类型:
         * (1) 如果 React Native 初始化发生在用户导航到 React Native 页面时,React 管理器会在初始化
         *     开始时进入 resumed 状态,因此 ReactContext.onHostResume() 会在这里执行。
         * (2) 如果 React Native 初始化发生在用户导航到 React Native 页面之前(即:React Native 被预加载),
         *     React 管理器在这里不会处于 resumed 状态。因此 ReactContext.onHostResume() 不会在这里执行。
         *     但是,当用户导航到他们的第一个 React Native 页面时,应用程序会调用 ReactHost.onHostResume()。
         *     那将会调用 ReactContext.onHostResume()。
         *
         * 重新加载阶段:如果管理器未处于 resumed 状态,则调用 ReactContext.onHostResume()。
         * 如果 React Native 正在重新加载,可以合理地假设:
         * (1) 我们过去一定导航到过某个 React Native 页面,或者
         * (2) 我们当前一定在某个 React Native 页面上。
         */
        if (isReloading && !isManagerResumed) {
          reactLifecycleStateManager.moveToOnHostResume(reactContext, currentActivity)
        } else {
          /**
           * 仅当已处于恢复状态时才调用 ReactContext.onHostResume(),
           * 这与桥接 https://fburl.com/diffusion/2qhxmudv 一致。
           */
          reactLifecycleStateManager.resumeReactContextIfHostResumed(reactContext, currentActivity)
        }

        stateTracker.enterState(method, "Executing ReactInstanceEventListeners")
        for (listener in reactInstanceEventListeners) {
          listener.onReactContextInitialized(reactContext)
        }
      }

      creationTask.continueWith(lifecycleUpdateTask, uiExecutor)
      // 提取 ReactInstance 并返回
      creationTask.onSuccess({ task -> checkNotNull(task.getResult()).instance })
    }
  }

getOrCreateReactInstanceTask方法的结构看起来比较复杂,实际上是因为使用了Facebook的Bolts-Android 库,通过Task类来模仿JS的Promise来实现异步的任务链式编程。具体内容,可以查看本系列第二篇文章《React Native 之Android端Bolts库》

这里我们只需从整体任务流来拆解,就能很好理解代码:

arduino 复制代码
═══════════════════════════════════════════════════════
createReactInstanceTaskRef.getOrCreate单例保证,只会执行一次
═══════════════════════════════════════════════════════

┌─────────────────────────────────────────────────────┐
│ Task Chain: 异步任务链                               │
├─────────────────────────────────────────────────────┤
│ jsBundleLoader (Task<JSBundleLoader>)               │
│   ↓ .onSuccess                                      │
│ creationTask (Task<CreationResult>)                 │
│   ├─ 创建 ReactContext                               │
│   ├─ 创建 ReactInstance                              │
│   ├─ 初始化 TurboModules (并行)                      │
│   └─ 加载 JS Bundle (并行)                           │
│   ↓ .continueWith                                   │
│ lifecycleUpdateTask (Lambda)                        │
│   ├─ 错误处理                                        │
│   ├─ 更新生命周期 (UI 线程)                          │
│   └─ 通知监听器                                      │
│   ↓ .onSuccess                                      │
│ Task<ReactInstance>                                 │
│   └─ 提取 instance 字段                              │
└─────────────────────────────────────────────────────┘

现在可以清晰的看到,主要有三个异步任务:jsBundleLoader加载、creationTasklifecycleUpdateTask在串行执行。先看一下jsBundleLoader任务:

kotlin 复制代码
private val jsBundleLoader: Task<JSBundleLoader>
    get() {
      stateTracker.enterState("getJSBundleLoader()")

      if (devSupportManager.bundleFilePath != null) {
        return try {
          Task.forResult(
              JSBundleLoader.createFileLoader(checkNotNull(devSupportManager.bundleFilePath))
          )
        } catch (e: Exception) {
          Task.forError(e)
        }
      }

      if (useDevSupport && allowPackagerServerAccess) {
        return isMetroRunning.onSuccessTask(
            { task ->
              val isMetroRunning = checkNotNull(task.getResult())
              if (isMetroRunning) {
                // 由于 Metro 正在运行,出现错误(method, "ReactContext is null. Reload
                // 原因:$h 从服务器加载 JS 包
                loadJSBundleFromMetro()
              } else {
                Task.forResult(reactHostDelegate.jsBundleLoader)
              }
            },
            bgExecutor,
        )
      } else {
        if (ReactBuildConfig.DEBUG) {
          FLog.d(TAG, "Packager server access is disabled in this environment")
        }

        /**
         * 生产模式下:回退到代理提供的 JS BundleLoader
         *
         * 注意:在 Task.call 中创建生产环境的 JSBundleLoader. 
         * 原因:如果 JSBundleLoader 创建过程中抛出异常,任务将会失败,我们将进入 ReactHost 的错误报告流程
         */
        return try {
          Task.forResult(reactHostDelegate.jsBundleLoader)
        } catch (e: Exception) {
          Task.forError(e)
        }
      }
    }

这里的逻辑主要是处理JS Bundle包加载。

现在,我们可以绘制一个完整的任务执行流,如下:

makefile 复制代码
T0: 方法被调用
    ├─ createReactInstanceTaskRef.getOrCreate { ... }
    └─ 检查单例:未创建 → 执行 Lambda

T1: jsBundleLoader 开始加载
    ├─ 如果是开发模式:从 Metro 服务器下载
    ├─ 如果是生产模式:使用打包的 Bundle
    └─ 返回 Task<JSBundleLoader>(未完成)

T2: jsBundleLoader 加载完成 
    └─ 触发 onSuccess 的 Lambda

T3: creationTask 开始执行(bgExecutor 线程)
    ├─ 创建 BridgelessReactContext
    ├─ 创建 ReactInstance 
    ├─ 设置内存压力监听 
    ├─ 并行初始化 Eager TurboModules           ┐
    │                                         ├─ 并行
    ├─ 加载 JS Bundle                         ┘
    └─ 通知 DevSupportManager 

T4: creationTask 完成 
    └─ 返回 CreationResult(instance, context, isReloading)

T5: continueWith 触发
    └─ 切换到 uiExecutor(UI 线程)

T6: lifecycleUpdateTask 执行(UI 线程)
    ├─ 检查错误:无错误 
    ├─ 更新生命周期:调用 onHostResume 
    └─ 通知监听器:所有 listeners 

T7: lifecycleUpdateTask 完成 

T8: onSuccess 提取 instance
    └─ 从 CreationResult 中提取 ReactInstance

T9: 方法返回 Task<ReactInstance>(已完成)
小结

ReactHostImpl 中的startSurface方法主要做了三件事:

  1. 创建ReactInstance的实例

  2. 加载JS的bundle包

  3. 调用ReactInstancestartSurface方法

ReactInstance

接下来我们需要聚焦ReactInstance对象的创建,这里面是核心逻辑,先来看一下构造参数:

kotlin 复制代码
val instance = ReactInstance(
                  reactContext,          // BridgelessReactContext
                  reactHostDelegate,     // DefaultReactHostDelegate
                  componentFactory,      // ComponentFactory
                  devSupportManager,     // DefaultDevSupportManagerFactory
                  { e: Exception -> this.handleHostException(e) },
                  useDevSupport,         // 是否是Debug模式启动
                  getOrCreateReactHostInspectorTarget(),  // ReactHostInspectorTarget
              )

注意,这里的reactHostDelegate实现类型是DefaultReactHostDelegate。下面我们仔细研究ReactInstance的初始化逻辑。

源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.kt

kotlin 复制代码
/**
 * 用于替代 [com.facebook.react.bridge.CatalystInstance],负责创建和管理 React Native 实例。
 */
@ThreadSafe
@DoNotStrip
@FrameworkAPI
@UnstableReactNativeAPI
internal class ReactInstance(
    private val context: BridgelessReactContext,
    delegate: ReactHostDelegate,
    componentFactory: ComponentFactory,
    devSupportManager: DevSupportManager,
    exceptionHandler: QueueThreadExceptionHandler,
    useDevSupport: Boolean,
    reactHostInspectorTarget: ReactHostInspectorTarget?,
) {
  @Suppress("NoHungarianNotation") @DoNotStrip private val mHybridData: HybridData

  private val turboModuleManager: TurboModuleManager
  private val javaTimerManager: JavaTimerManager
  private val viewManagerResolver: BridgelessViewManagerResolver

  val reactQueueConfiguration: ReactQueueConfiguration
  val fabricUIManager: FabricUIManager
  val javaScriptContextHolder: JavaScriptContextHolder

  init {
    Systrace.beginSection(Systrace.TRACE_TAG_REACT, "ReactInstance.initialize")

    /**
     * 通过安装 JSI 绑定、初始化 Fabric + TurboModules 以及加载 JS bundle 来准备 ReactInstance
     */
    val spec =
        ReactQueueConfigurationSpec(
            MessageQueueThreadSpec.newBackgroundThreadSpec("v_native"),
            MessageQueueThreadSpec.newBackgroundThreadSpec("v_js"),
        )
    reactQueueConfiguration = ReactQueueConfigurationImpl.create(spec, exceptionHandler)
    FLog.d(TAG, "Calling initializeMessageQueueThreads()")
    context.initializeMessageQueueThreads(reactQueueConfiguration)
    val jsMessageQueueThread = reactQueueConfiguration.getJSQueueThread()
    val nativeModulesMessageQueueThread = reactQueueConfiguration.getNativeModulesQueueThread()

    ReactChoreographer.initialize(AndroidChoreographerProvider.getInstance())
    devSupportManager.startInspector()

    val jsTimerExecutor = JSTimerExecutor()
    javaTimerManager =
        JavaTimerManager(
            context,
            jsTimerExecutor,
            ReactChoreographer.getInstance(),
            devSupportManager,
        )

    // 如果启用了性能分析,通知 JS
    val isProfiling =
        BuildConfig.ENABLE_PERFETTO ||
            Systrace.isTracing(Systrace.TRACE_TAG_REACT) ||
            getIsProfilingBuild()

    mHybridData =
        initHybrid(
            delegate.jsRuntimeFactory,
            jsMessageQueueThread,
            nativeModulesMessageQueueThread,
            javaTimerManager,
            jsTimerExecutor,
            ReactJsExceptionHandlerImpl(exceptionHandler),
            delegate.bindingsInstaller,
            isProfiling,
            reactHostInspectorTarget,
        )

    javaScriptContextHolder = JavaScriptContextHolder(getJavaScriptContext())

    // 设置 TurboModules
    Systrace.beginSection(Systrace.TRACE_TAG_REACT, "ReactInstance.initialize#initTurboModules")

    val reactPackages: MutableList<ReactPackage> = ArrayList<ReactPackage>()
    reactPackages.add(
        CoreReactPackage(context.devSupportManager, context.defaultHardwareBackBtnHandler)
    )
    if (useDevSupport) {
      reactPackages.add(DebugCorePackage())
    }
    reactPackages.addAll(delegate.reactPackages)

    val turboModuleManagerDelegate =
        delegate.turboModuleManagerDelegateBuilder
            .setPackages(reactPackages)
            .setReactApplicationContext(context)
            .build()

    val unbufferedRuntimeExecutor = getUnbufferedRuntimeExecutor()
    turboModuleManager =
        TurboModuleManager( // 使用 unbuffered RuntimeExecutor 来安装绑定
            unbufferedRuntimeExecutor,
            turboModuleManagerDelegate,
            getJSCallInvokerHolder(),
            getNativeMethodCallInvokerHolder(),
        )
    Systrace.endSection(Systrace.TRACE_TAG_REACT)

    // 设置 Fabric
    Systrace.beginSection(Systrace.TRACE_TAG_REACT, "ReactInstance.initialize#initFabric")

    viewManagerResolver = BridgelessViewManagerResolver(reactPackages, context)

    // 为 JS 的 UIManager.hasViewManagerConfig() 初始化函数
    // 使用 unbuffered RuntimeExecutor 来安装绑定
    ComponentNameResolverBinding.install(
        unbufferedRuntimeExecutor,
        object : ComponentNameResolver {
          override val componentNames: Array<String>
            get() {
              val viewManagerNames = viewManagerResolver.getViewManagerNames()
              if (viewManagerNames.isEmpty()) {
                FLog.e(TAG, "No ViewManager names found")
                return arrayOf()
              }
              return viewManagerNames.toTypedArray<String>()
            }
        },
    )

    // 为 JS 的 UIManager.getViewManagerConfig() 初始化函数
    // 这应该在 getTurboModuleManagerDelegate 之后执行,因为它依赖于 react packages 被初始化
    // 这发生在 getTurboModuleManagerDelegate getter 内部
    if (ReactNativeFeatureFlags.useNativeViewConfigsInBridgelessMode()) {
      val customDirectEvents: MutableMap<String, Any> = HashMap()

      UIConstantsProviderBinding.install(
          // 使用 unbuffered RuntimeExecutor 来安装绑定
          unbufferedRuntimeExecutor,
          // 这里我们正在构建 UIManager.getConstants 调用的返回值
          // 旧架构依赖于 constants 结构体包含:
          // 1. 所有原生组件的预加载视图配置
          // 2. genericBubblingEventTypes(通用冒泡事件类型)
          // 3. genericDirectEventTypes(通用直接事件类型)
          // 我们想要匹配这种行为
          { Arguments.makeNativeMap(UIManagerModuleConstantsHelper.defaultExportableEventTypes) },
          ConstantsForViewManagerProvider { viewManagerName: String ->
            val viewManager =
                viewManagerResolver.getViewManager(viewManagerName)
                    ?: return@ConstantsForViewManagerProvider null
            getConstantsForViewManager(viewManager, customDirectEvents)
          },
          {
            val viewManagers: List<ViewManager<*, *>> =
                ArrayList(viewManagerResolver.eagerViewManagerMap.values)
            val constants = createConstants(viewManagers, customDirectEvents)

            val lazyViewManagers = viewManagerResolver.lazyViewManagerNames
            if (!lazyViewManagers.isEmpty()) {
              constants["ViewManagerNames"] = ArrayList(lazyViewManagers)
              constants["LazyViewManagersEnabled"] = true
            }
            Arguments.makeNativeMap(constants)
          },
      )
    }

    val eventBeatManager = EventBeatManager()
    fabricUIManager =
        FabricUIManager(context, ViewManagerRegistry(viewManagerResolver), eventBeatManager)

    // 在 Fabric 初始化之前需要完成的其他初始化
    DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)

    val binding = FabricUIManagerBinding()
    binding.register(
        getBufferedRuntimeExecutor(),
        getRuntimeScheduler(),
        fabricUIManager,
        eventBeatManager,
        componentFactory,
    )

    // 初始化 FabricUIManager
    fabricUIManager.initialize()

    Systrace.endSection(Systrace.TRACE_TAG_REACT)
    Systrace.endSection(Systrace.TRACE_TAG_REACT)
  }

  // 省略......
}

这段初始化代码,大概可以分为5个阶段:

  1. 线程创建

    kotlin 复制代码
        val spec = ReactQueueConfigurationSpec(
                        MessageQueueThreadSpec.newBackgroundThreadSpec("v_native"),
                        MessageQueueThreadSpec.newBackgroundThreadSpec("v_js"),
                    )
        reactQueueConfiguration = ReactQueueConfigurationImpl.create(spec, exceptionHandler)
        context.initializeMessageQueueThreads(reactQueueConfiguration)
    • 创建两个后台线程:v_native (Native模块线程)和 v_js(JS线程)
    • 初始化消息队列
  2. 初始化基础设施

    kotlin 复制代码
      ReactChoreographer.initialize(AndroidChoreographerProvider.getInstance())
      devSupportManager.startInspector()
    
      val jsTimerExecutor = JSTimerExecutor()
      javaTimerManager =
          JavaTimerManager(
              context,
              jsTimerExecutor,
              ReactChoreographer.getInstance(),
              devSupportManager,
          )
    • 初始化 ReactChoreographer(用于同步动画和布局)

    • 启动 Inspector(开发工具)

    • 创建 JavaTimerManager(处理 JS 定时器)

  3. 初始化 Native 层 (HybridData)

    kotlin 复制代码
      mHybridData = initHybrid(
                        delegate.jsRuntimeFactory,
                        jsMessageQueueThread,
                        nativeModulesMessageQueueThread,
                        javaTimerManager,
                        jsTimerExecutor,
                        ReactJsExceptionHandlerImpl(exceptionHandler),
                        delegate.bindingsInstaller,
                        isProfiling,
                        reactHostInspectorTarget,
                    )
      javaScriptContextHolder = JavaScriptContextHolder(getJavaScriptContext())
    • 调用 native 方法 initHybrid 创建 C++ 层的 ReactInstance 对象

    • 获取 JavaScript 上下文句柄

  4. 初始化 TurboModule 系统

    主要代码在turboModuleManagerDelegateturboModuleManager的创建前后。

    • 构建 ReactPackage 列表(包括核心包和开发包)

    • 创建 TurboModuleManagerDelegate

    • 初始化 TurboModuleManager,这是新架构中 Native 模块的管理器

  5. 初始化 Fabric UI 系统

    • 创建 ViewManager 解析器:用于按需加载和管理所有的 ViewManager
    • 安装 ComponentNameResolver 绑定:允许 JS 端调用 UIManager.hasViewManagerConfig() 方法
    • 安装 UIConstantsProvider 绑定
    • 创建并初始化 FabricUIManager

对于TurboModule 系统和Fabric UI 系统,我们在后面单独章节研究。现在来看一下initHybrid方法。此方法是一个native方法,由JNI层面C++实现。方法返回一个HybridData类型对象。这里HybridData来自由Facebook开源的另一个库 fbjni。此库的介绍:

Facebook JNI 辅助库旨在简化 Java 本地接口 (JNI) 的使用。这些辅助库的实现是为了方便在 Android 上集成跨平台移动代码,但其设计并不针对 Android 平台。它可以与任何支持 JNI 的 Java 虚拟机 (JVM) 一起使用。

简单说,JVM的JNI接口设计得非常冗长繁琐,直接使用JNI接口代码量会大大增加。fbjni库就是对JNI接口的封装,简化调用。

这里HybridData 就是fbjni提供的 JNI 桥接类

java 复制代码
class HybridData {
   static {
     NativeLoader.loadLibrary("fbjni");
   }

    // 持有 C++ 对象的指针
    private long mNativePointer;  // C++ 对象的内存地址

    // 省略......
}

参考以下架构图:

scss 复制代码
┌─────────────────────────────────────────────────────────┐
│                  React Native 架构                       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Java/Kotlin 层                                         │
│  ┌──────────────────────────────┐                        │
│  │  ReactInstance               │                        │
│  │  ├─ mHybridData ────────┐    │                        │
│  │  ├─ turboModuleManager  │    │                        │
│  │  └─ fabricUIManager     │    │                        │
│  └─────────────────────────┘    │                        │
│           │                     │                        │
│           │ (JNI/fbjni)         │                        │
│           ↓                     │                        │
│  ┌──────────────────────────┐   │  ← HybridData 桥接     │
│  │  HybridData              │───┘                        │
│  │  持有 C++ 智能指针         │                             │
│  └──────────────────────────┘                             │
│           │                                                │
│           ↓                                                │
│  C++ 层                                                    │
│  ┌──────────────────────────┐                             │
│  │  ReactInstance (C++)     │                             │
│  │  ├─ JSI Runtime          │                             │
│  │  ├─ TurboModules         │                             │
│  │  └─ Fabric               │                             │
│  └──────────────────────────┘                             │
│           │                                                │
│           │ (JSI)                                          │
│           ↓                                                │
│  JavaScript 层                                             │
│  ┌──────────────────────────┐                             │
│  │  React Components        │                             │
│  └──────────────────────────┘                             │
└─────────────────────────────────────────────────────────┘

主要作用就是桥接 C++ 对象

  • 持有 C++ 对象指针:保存对应的 C++ ReactInstance 对象的智能指针
  • 生命周期管理:确保 C++ 对象与 Java 对象同步创建和销毁
  • JNI 桥接:作为 Java 调用 C++ 方法的桥梁(通过 native 方法)
  • 内存管理:防止 C++ 对象被过早释放,避免悬空指针

注意

  • 字段名必须是 "mHybridData"(fbjni 通过反射查找此名称)
  • 通过native 方法 initHybrid()初始化,返回持有 C++ 对象的 HybridData
  • 调用 resetNative() 释放 C++ 资源(在 destroy() 中)
  • 使用注解@DoNotStrip 防止 ProGuard 混淆/删除此字段

Java对象与C++对象的对应关系,可以查看源码 Hybrid.h#L310

关于C++侧的详细分析放到后面,这里先看看startSurface方法的调用:

kotlin 复制代码
 // ReactInstance.kt

 /**
   * 渲染一个 React Native surface.
   *
   * @param surface 要渲染的 [com.facebook.react.interfaces.fabric.ReactSurface] 对象
   */
  @ThreadConfined("ReactHost")
  fun startSurface(surface: ReactSurfaceImpl) {
    FLog.d(TAG, "startSurface() is called with surface: ${surface.surfaceID}")
    Systrace.beginSection(Systrace.TRACE_TAG_REACT, "ReactInstance.startSurface")

    val view = surface.view
    checkNotNull(view) {
      "Starting surface without a view is not supported, use prerenderSurface instead."
    }

    /**
     * 这是针对 646912b2590a6d5e760316cc064d1e27 的临时缓解措施,,
     *
     * <p>TODO T83828172 调查为什么 surface.getView() 的 ID 不等于 View.NO_ID
     */
    if (view.id != View.NO_ID) {
      ReactSoftExceptionLogger.logSoftException(
          TAG,
          IllegalViewOperationException(
              "surfaceView's is NOT equal to View.NO_ID before calling startSurface."
          ),
      )
      view.id = View.NO_ID
    }
    if (surface.isRunning) {
      // Surface 已经在运行(预渲染过),只需附加 View
      fabricUIManager.attachRootView(surface.surfaceHandler, view)
    } else {
      fabricUIManager.startSurface(surface.surfaceHandler, surface.context, view)
    }
    Systrace.endSection(Systrace.TRACE_TAG_REACT)
  }

这个方法的核心功能是:启动并渲染一个 React Native 界面(Surface)到 Android View 上。

但要注意,这里注解指明,该方法只能在ReactHost的后台线程上调用。具体来说,就是以下源码处:

kotlin 复制代码
    return callAfterGetOrCreateReactInstance(method, bgExecutor) { reactInstance: ReactInstance ->
      stateTracker.enterState(method, "Execute")
      reactInstance.startSurface(surface)
    }
小结

ReactInstance 的创建做了很多事,概括一下,其实主要是四点:

  • 创建后台工作线程

  • 初始化 TurboModule 系统

  • 初始化 Fabric UI 系统

  • 启动并渲染React Native 界面

C++ 侧

如何找到ReactInstance 中native方法initHybrid对应的C++实现?

第一步,自然是定位到其加载的动态库:

kotlin 复制代码
// ReactInstance.kt


    init {
      /**
       * 加载 rninstance 动态库
       * 
       * 该库包含:
       * 1. ReactInstance 的所有 JNI native 方法实现(如 initHybrid、loadJSBundle 等)
       * 2. C++ ReactInstance 类的实现
       * 3. JSI Runtime 的初始化代码
       * 4. TurboModule 和 Fabric 的 C++ 层实现
       * 
       * 必须在类加载时调用,确保 native 方法可用
       */
      SoLoader.loadLibrary("rninstance")
    }

第二步,全局搜索定义了rninstance库名称的CMakeLists.txt文件:

react-native/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt

cmake 复制代码
file(GLOB_RECURSE bridgeless_jni_SRC CONFIGURE_DEPENDS *.cpp)

add_library(rninstance
        OBJECT
        ${bridgeless_jni_SRC}
)

CMakeLists.txt是用于构建C++代码的配置文件,类似于Gradle脚本与Kotlin的关系。这里的两行代码,首先是递归查找当前路径下的所有.cpp文件,然后将文件列表保存到一个变量bridgeless_jni_SRC中,第二行则是将找到的.cpp源文件全部编译成一个rninstance 对象文件。这里了解C/C++开发的人一定会有疑惑,前面不是说在kotlin中加载动态库rninstance吗?现在构建脚本怎么是编译成对象文件,这可跟动态库不是一回事了?

其实我们继续搜索rninstance 关键字就会发现,在另外一个更外层配置文件react-native/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt中,有如下内容:

cmake 复制代码
# libreactnative.so 依赖项
#
# React Native Android 库(.aar 文件)应该仅通过此目标公开头文件。
# 这样做是为了减少最终库中包含的 .so 文件数量。
add_library(reactnative
        SHARED
          $<TARGET_OBJECTS:bridgeless>
          $<TARGET_OBJECTS:bridgelessnativeviewconfig>
          $<TARGET_OBJECTS:callinvokerholder>
          $<TARGET_OBJECTS:fabricjni>
          $<TARGET_OBJECTS:glog_init>
          $<TARGET_OBJECTS:jni_lib_merge_glue>
          $<TARGET_OBJECTS:jserrorhandler>
          $<TARGET_OBJECTS:jsinspector>
          # 省略......
          $<TARGET_OBJECTS:rninstance>
          # 省略......
          $<TARGET_OBJECTS:runtimeexecutor>
          $<TARGET_OBJECTS:turbomodulejsijni>
          $<TARGET_OBJECTS:uimanagerjni>
          $<TARGET_OBJECTS:yoga>
)
target_merge_so(reactnative)

可以看到,对象文件rninstance 最终被合并到了动态库reactnative 中。注释也告诉我们,这样做是为了减少动态库文件的数量。那么SoLoader.loadLibrary("rninstance")又是如何正确的找到reactnative 动态库的呢?这就需要来研究Facebaook另外一个开源库SoLoader的源码了。SoLoader.java#L891

java 复制代码
// SoLoader.java

  public static void init(Context context, @Nullable ExternalSoMapping externalSoMapping) {
    synchronized (SoLoader.class) {
      SoLoader.externalSoMapping = externalSoMapping;
    }
    try {
      init(context, 0);
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    }
  }

  public static void init(Context context,int flags,@Nullable SoFileLoader soFileLoader,@Nullable Provider<ApplicationInfo> applicationInfoProvider)
      throws IOException {
    if (isInitialized()) {
      LogUtil.w(TAG, "SoLoader already initialized");
      return;
    }

    try {
      isEnabled = initEnableConfig(context);
      // 省略......
    }
  }

  /**
   * 确定是否启用 soloader
   */
  private static boolean initEnableConfig(Context context) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
      return true;
    }

    if (SoLoader.externalSoMapping != null) {
      // 此用例适用于使用开源 SoMerging 的 React Native 应用程序。
      // 如果已提供 externalSoMapping,则无需检查 Manifest 文件中是否启用了 SoLoader。
      return true;
    }
    // 省略......
  }

  public static boolean loadLibrary(String shortName) {
    return isEnabled ? loadLibrary(shortName, 0) : NativeLoader.loadLibrary(shortName);
  }

在本文开头分析入口代码自动生成的地方,loadReactNative()方法调用处,我们已经见过了SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE)初始化代码,再结合以上代码的官方注释,当初始化传入externalSoMapping对象时,默认启用SoLoader ,所以接下来就需要跟踪loadLibrary(shortName, 0)。由于本文主要分析React Native初始化,这里就不再详细分析SoLoader 的实现源码,后面在其他章节专门研究SoLoader 。先简要看一下loadLibrary实现:

java 复制代码
  /**
   * 加载动态库,并初始化其中包含的任何 JNI 绑定。
   *
   * @param shortName 要查找的库的名称,不包含"lib"前缀或".so"后缀。
   * @param loadFlags 用于控制加载行为的标志。可用的标志请参见 {@link  SoSource} (LOAD_FLAG_XXX).
   */
  public static boolean loadLibrary(String shortName, int loadFlags) throws UnsatisfiedLinkError {
    // 省略......
    return loadLibraryOnAndroid(shortName, loadFlags);
  }

  private static boolean loadLibraryOnAndroid(String shortName, int loadFlags) {
    @Nullable Throwable failure = null;
    String mergedLibName;
    if (externalSoMapping != null) {
      mergedLibName = externalSoMapping.mapLibName(shortName);
    } else {
      mergedLibName = MergedSoMapping.mapLibName(shortName);
    }
    String soName = mergedLibName != null ? mergedLibName : shortName;
    ObserverHolder.onLoadLibraryStart(shortName, mergedLibName, loadFlags);
    boolean wasLoaded = false;
    try {
      wasLoaded =
          loadLibraryBySoName(
              System.mapLibraryName(soName), shortName, mergedLibName, loadFlags, null);
      return wasLoaded;
    } catch (Throwable t) {
      failure = t;
      throw t;
    } finally {
      ObserverHolder.onLoadLibraryEnd(failure, wasLoaded);
    }
  }

这里可以看到,当传入了externalSoMapping时,使用的就是该实例提供的mapLibName方法查找映射的库名称。查看react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt

kotlin 复制代码
  public override fun mapLibName(input: String): String =
      when (input) {
        "fabricjni",
        "jsinspector",
        "mapbufferjni",
        "react_devsupportjni",
        "react_featureflagsjni",
        "react_newarchdefaults",
        "reactnativeblob",
        "reactnativejni",
        "reactnativejni_common",
        "rninstance",
        "turbomodulejsijni",
        "uimanagerjni",
        "yoga" -> {
          "reactnative"
        }
        "hermes_executor",
        "hermesinstancejni",
        "jsijniprofiler" -> {
          "hermestooling"
        }
        else -> input
      }

可见,当查找的是"rninstance"时,返回的实际上是动态库"reactnative"。在SoLoader 库中,最后经过一系列复杂的处理和调用,最终仍然是通过 System.load 来加载动态库。SoLoader 库年头算是比较久了,其中有大量代码用于处理各种兼容性问题,包括不同的安卓版本,不同的环境(安卓或JVM)等等,以致于其中代码处理十分复杂,成了一座屎山。所以具体的SoLoader加载调用链路我们这里就略过了。

第三步,既然定位到了rninstance 源码目录,直接查看头文件react-native/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h和实现文件react-native/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp

cpp 复制代码
// JReactInstance.h

class JReactInstance : public jni::HybridClass<JReactInstance> {
 public:
  constexpr static auto kJavaDescriptor = "Lcom/facebook/react/runtime/ReactInstance;";

  static jni::local_ref<jhybriddata> initHybrid(
      jni::alias_ref<jhybridobject> /*unused*/,
      jni::alias_ref<JJSRuntimeFactory::javaobject> jsRuntimeFactory,
      jni::alias_ref<JavaMessageQueueThread::javaobject> jsMessageQueueThread,
      jni::alias_ref<JavaMessageQueueThread::javaobject> nativeMessageQueueThread,
      jni::alias_ref<JJavaTimerManager::javaobject> javaTimerManager,
      jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
      jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
      jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
      bool isProfiling,
      jni::alias_ref<JReactHostInspectorTarget::javaobject> jReactHostInspectorTarget);

  static void registerNatives();

  void loadJSBundleFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager, const std::string &assetURL);

  void loadJSBundleFromFile(const std::string &fileName, const std::string &sourceURL);

  void callFunctionOnModule(const std::string &moduleName, const std::string &methodName, NativeArray *args);
  // 省略......
};

注意,这里initHybrid是一个静态方法,关于上层Kotlin是如何关联到此方法的,这里面大有讲究。如果了解JNI调用,那么就知道,此处是不符合JNI的Native方法绑定规则,想必越是熟悉JNI开发,越是对此困惑。实际上这里面搞了相当多的骚操作,我们放到本章最后再来详细解谜,这里优先关注React Native的核心初始化流程。

首先JReactInstance继承自jni::HybridClass类,此类使用了 C++ 的 CRTP模式(Curiously Recurring Template Pattern,奇异递归模板模式)。所以这里子类将自己作为模板参数传了进去,这点后面很重要 。简单的理解,就相当于在父类指定了一个泛型,泛型的类型就是当前的子类。这里面使用了fbjni 提供的机制,前面也提到过,JReactInstance 实际上就相当于一个胶水层,将kotlin的ReactInstance 类和C++层的ReactInstance类关联起来,实现互相调用,互相通信。

cpp 复制代码
// JReactInstance.cpp

jni::local_ref<JReactInstance::jhybriddata> JReactInstance::initHybrid(
    jni::alias_ref<jhybridobject> /* unused */,
    jni::alias_ref<JJSRuntimeFactory::javaobject> jsRuntimeFactory,
    jni::alias_ref<JavaMessageQueueThread::javaobject> jsMessageQueueThread,
    jni::alias_ref<JavaMessageQueueThread::javaobject> nativeMessageQueueThread,
    jni::alias_ref<JJavaTimerManager::javaobject> javaTimerManager,
    jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
    jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
    jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
    bool isProfiling,
    jni::alias_ref<JReactHostInspectorTarget::javaobject>
        jReactHostInspectorTarget) {
  return makeCxxInstance(
      jsRuntimeFactory,
      jsMessageQueueThread,
      nativeMessageQueueThread,
      javaTimerManager,
      jsTimerExecutor,
      jReactExceptionManager,
      jBindingsInstaller,
      isProfiling,
      jReactHostInspectorTarget);
}

在实现代码中,首先关注initHybrid方法,其作用就是使用fbjni提供的makeCxxInstance方法创建了一个JReactInstance实例:

cpp 复制代码
  template <typename... Args>
  static local_ref<detail::HybridData> makeCxxInstance(Args&&... args) {
    return makeHybridData(
        std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
  }

这是一个模版方法,其核心就是创建了一个类型T 的实例对象。这里的T ,就是前面强调的CRTP模式传入的模版参数,所以这里就是在new一个 JReactInstance 实例。最后又调用makeHybridData方法包了一层返回给kotlin层持有,实际上就是包装成一个适合kotlin持有的智能指针。

接下来,重点就要关注JReactInstance的构造方法了:

cpp 复制代码
JReactInstance::JReactInstance(
    jni::alias_ref<JJSRuntimeFactory::javaobject> jsRuntimeFactory,              // JS 引擎工厂(Hermes/JSC)
    jni::alias_ref<JavaMessageQueueThread::javaobject> jsMessageQueueThread,     // JS 线程
    jni::alias_ref<JavaMessageQueueThread::javaobject> nativeMessageQueueThread, // Native 线程
    jni::alias_ref<JJavaTimerManager::javaobject> javaTimerManager,              // Java 定时器管理
    jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,                // JS 定时器执行器
    jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,   // 异常管理
    jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,           // 自定义绑定安装器
    bool isProfiling,                                                            // 是否开启性能分析
    jni::alias_ref<JReactHostInspectorTarget::javaobject> jReactHostInspectorTarget  // 调试器
) noexcept {
  // TODO(janzer): Lazily create runtime
  // 创建消息队列线程包装器
  auto sharedJSMessageQueueThread =
      std::make_shared<JMessageQueueThread>(jsMessageQueueThread);
  auto sharedNativeMessageQueueThread =
      std::make_shared<JMessageQueueThread>(nativeMessageQueueThread);

  // 创建定时器管理器 (for JS timers)
  auto timerRegistry =
      std::make_unique<JavaTimerRegistry>(jni::make_global(javaTimerManager));
  auto timerManager = std::make_shared<TimerManager>(std::move(timerRegistry));
  jsTimerExecutor->cthis()->setTimerManager(timerManager);

  // 设置 JS 错误处理回调
  jReactExceptionManager_ = jni::make_global(jReactExceptionManager);
  auto onJsError =
      [weakJReactExceptionManager = jni::make_weak(jReactExceptionManager)](
          jsi::Runtime& runtime,
          const JsErrorHandler::ProcessedError& error) mutable noexcept {
        if (auto jReactExceptionManager =
                weakJReactExceptionManager.lockLocal()) {
          jReactExceptionManager->reportJsException(runtime, error);
        }
      };

  jBindingsInstaller_ = jni::make_global(jBindingsInstaller);

  // 创建核心 ReactInstance
  instance_ = std::make_unique<ReactInstance>(
      jsRuntimeFactory->cthis()->createJSRuntime(sharedJSMessageQueueThread),
      sharedJSMessageQueueThread,
      timerManager,
      std::move(onJsError),
      jReactHostInspectorTarget
          ? jReactHostInspectorTarget->cthis()->getInspectorTarget()
          : nullptr);

  // 设置定时器的 RuntimeExecutor
  auto bufferedRuntimeExecutor = instance_->getBufferedRuntimeExecutor();
  timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);

  // 初始化 JS Runtime
  ReactInstance::JSRuntimeFlags options = {.isProfiling = isProfiling};
  // TODO T194671568 Consider moving runtime init to the JS thread.
  instance_->initializeRuntime(options, [this](jsi::Runtime& runtime) {
    // 绑定 Android 日志系统
    react::Logger androidLogger =
        static_cast<void (*)(const std::string&, unsigned int)>(
            &reactAndroidLoggingHook);
    react::bindNativeLogger(runtime, androidLogger);
    if (jBindingsInstaller_ != nullptr) {
      auto appBindingInstaller =
          jBindingsInstaller_->cthis()->getBindingsInstallFunc();
      if (appBindingInstaller != nullptr) {
        appBindingInstaller(runtime);
      }
    }
  });

  auto unbufferedRuntimeExecutor = instance_->getUnbufferedRuntimeExecutor();
  // 创建调用器(用于 TurboModules)
  auto jsInvoker = std::make_unique<RuntimeSchedulerCallInvoker>(
      instance_->getRuntimeScheduler());
  jsCallInvokerHolder_ = jni::make_global(
      CallInvokerHolder::newObjectCxxArgs(std::move(jsInvoker)));
  auto nativeMethodCallInvoker =
      std::make_unique<BridgelessNativeMethodCallInvoker>(
          sharedNativeMessageQueueThread);
  nativeMethodCallInvokerHolder_ = jni::make_global(
      NativeMethodCallInvokerHolder::newObjectCxxArgs(
          std::move(nativeMethodCallInvoker)));

  // 创建 RuntimeExecutor 包装器
  // 将它存储在这里是为了确保 Java 引用不会被销毁。
  unbufferedRuntimeExecutor_ = jni::make_global(
      JRuntimeExecutor::newObjectCxxArgs(unbufferedRuntimeExecutor));
  bufferedRuntimeExecutor_ = jni::make_global(
      JRuntimeExecutor::newObjectCxxArgs(bufferedRuntimeExecutor));
  runtimeScheduler_ = jni::make_global(
      JRuntimeScheduler::newObjectCxxArgs(instance_->getRuntimeScheduler()));
}

以上流程非常清晰,我已经添加了一部分注释。接下来重点看一下ReactInstance 构造部分,react-native/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp

cpp 复制代码
ReactInstance::ReactInstance(
    std::unique_ptr<JSRuntime> runtime,
    std::shared_ptr<MessageQueueThread> jsMessageQueueThread,
    std::shared_ptr<TimerManager> timerManager,
    JsErrorHandler::OnJsError onJsError,
    jsinspector_modern::HostTarget* parentInspectorTarget)
    : runtime_(std::move(runtime)),
      jsMessageQueueThread_(std::move(jsMessageQueueThread)),
      timerManager_(std::move(timerManager)),
      jsErrorHandler_(std::make_shared<JsErrorHandler>(std::move(onJsError))),
      parentInspectorTarget_(parentInspectorTarget) {

  // 创建 RuntimeExecutor(核心逻辑)
  RuntimeExecutor runtimeExecutor =
      [weakRuntime = std::weak_ptr(runtime_),
       weakTimerManager = std::weak_ptr(timerManager_),
       weakJsThread = std::weak_ptr(jsMessageQueueThread_),
       jsErrorHandler = jsErrorHandler_](auto callback) {
        // 检查 runtime 是否还存活
        if (weakRuntime.expired()) {
          return;
        }

        if (auto jsThread = weakJsThread.lock()) {
          // 在 JS 线程上执行
          jsThread->runOnQueue([jsErrorHandler,
                                weakRuntime,
                                weakTimerManager,
                                callback = std::move(callback)]() {
            auto runtime = weakRuntime.lock();
            if (!runtime) {
              return;
            }

            jsi::Runtime& jsiRuntime = runtime->getRuntime();
            TraceSection s("ReactInstance::_runtimeExecutor[Callback]");
            try {
              ShadowNode::setUseRuntimeShadowNodeReferenceUpdateOnThread(true);
              callback(jsiRuntime);   // 执行回调
            } catch (jsi::JSError& originalError) {
              jsErrorHandler->handleError(jsiRuntime, originalError, true);
            } catch (std::exception& ex) {
              // 捕获 C++ 异常,转换为 JS 错误
              jsi::JSError error(
                  jsiRuntime, std::string("Non-js exception: ") + ex.what());
              jsErrorHandler->handleError(jsiRuntime, error, true);
            }
          });
        }
      };

   // 有调试器的情况
  if (parentInspectorTarget_ != nullptr) {
    auto executor = parentInspectorTarget_->executorFromThis();

    auto bufferedRuntimeExecutorThatWaitsForInspectorSetup =
        std::make_shared<BufferedRuntimeExecutor>(runtimeExecutor);
    auto runtimeExecutorThatExecutesAfterInspectorSetup =
        [bufferedRuntimeExecutorThatWaitsForInspectorSetup](
            std::function<void(jsi::Runtime & runtime)>&& callback) {
          bufferedRuntimeExecutorThatWaitsForInspectorSetup->execute(
              std::move(callback));
        };

    // 创建 RuntimeScheduler
    runtimeScheduler_ = createRuntimeScheduler(
        runtimeExecutorThatExecutesAfterInspectorSetup,
        [jsErrorHandler = jsErrorHandler_](
            jsi::Runtime& runtime, jsi::JSError& error) {
          jsErrorHandler->handleError(runtime, error, true);
        });

    auto runtimeExecutorThatGoesThroughRuntimeScheduler =
        [runtimeScheduler = runtimeScheduler_.get()](
            std::function<void(jsi::Runtime & runtime)>&& callback) {
          runtimeScheduler->scheduleWork(std::move(callback));
        };

    // 这段代码可能从任意线程执行,因此我们需要确保在正确的线程中设置调试器逻辑。
    // 如果当前已经在正确的线程中,回调会立即执行
    executor([this,
              runtimeExecutorThatGoesThroughRuntimeScheduler,
              bufferedRuntimeExecutorThatWaitsForInspectorSetup](
                 jsinspector_modern::HostTarget& hostTarget) {
      // 通过 page target executor 调度的回调通常不保证一定会执行
      // (例如:如果 page target 被销毁了)
      // 但在这个场景下,回调是保证会执行的,因为 page target 不可能在实例完成初始化之前被销毁:
      // * 在 iOS 上,这是因为我们同步地进行初始化设置
      // * 在 Android 上,这是因为我们会显式等待实例创建任务完成后,才开始销毁流程
      inspectorTarget_ = &hostTarget.registerInstance(*this);
      runtimeInspectorTarget_ = &inspectorTarget_->registerRuntime(
          runtime_->getRuntimeTargetDelegate(),
          runtimeExecutorThatGoesThroughRuntimeScheduler);
      bufferedRuntimeExecutorThatWaitsForInspectorSetup->flush();
    });
  } else {
    // 没有调试器的情况
    runtimeScheduler_ = createRuntimeScheduler(
        runtimeExecutor,
        [jsErrorHandler = jsErrorHandler_](
            jsi::Runtime& runtime, jsi::JSError& error) {
          jsErrorHandler->handleError(runtime, error, true);
        });
  }

  // 在 JS Bundle 加载完成前,缓冲所有的 JS 调用,加载完成后再执行
  bufferedRuntimeExecutor_ = std::make_shared<BufferedRuntimeExecutor>(
      [runtimeScheduler = runtimeScheduler_.get()](
          std::function<void(jsi::Runtime & runtime)>&& callback) {
        runtimeScheduler->scheduleWork(std::move(callback));
      });
}

这其中,RuntimeExecutor非常重要,这里可以看到是一个lambda函数,相当于一个闭包。它的主要作用是:

  1. 接收一个 callback(需要在 JS 线程执行的函数)

  2. 将 callback 调度到 JS 线程

  3. 执行时自动处理异常

小结

最后,总结一下C++侧的初始化流程:

css 复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                        JReactInstance 创建流程                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Java: ReactInstance.kt                                                     │
│         │                                                                   │
│         ▼                                                                   │
│  initHybrid(jsRuntimeFactory, jsThread, nativeThread, ...)                 │
│         │                                                                   │
│         ▼                                                                   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ JReactInstance 构造函数                                              │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                     │   │
│  │  ① 包装 Java 线程 → C++ MessageQueueThread                          │   │
│  │                                                                     │   │
│  │  ② 创建 TimerManager ← JavaTimerRegistry ← JavaTimerManager        │   │
│  │                                                                     │   │
│  │  ③ 创建 onJsError 回调 (JS 错误 → Java 红屏)                         │   │
│  │                                                                     │   │
│  │  ④ 创建 ReactInstance ───────────────────────┐                      │   │
│  │         │                                    │                      │   │
│  │         ▼                                    ▼                      │   │
│  │  ┌──────────────────────────────────────────────────────────────┐  │   │
│  │  │ ReactInstance 构造函数                                        │  │   │
│  │  ├──────────────────────────────────────────────────────────────┤  │   │
│  │  │                                                              │  │   │
│  │  │  (a) 保存 runtime_, jsMessageQueueThread_, timerManager_    │  │   │
│  │  │                                                              │  │   │
│  │  │  (b) 创建 RuntimeExecutor (核心调度器)                        │  │   │
│  │  │      - 捕获弱引用防止循环引用                                  │  │   │
│  │  │      - 将任务调度到 JS 线程                                   │  │   │
│  │  │      - 自动捕获异常并处理                                     │  │   │
│  │  │                                                              │  │   │
│  │  │  (c) 创建 RuntimeScheduler                                   │  │   │
│  │  │      - 任务优先级调度                                         │  │   │
│  │  │      - 与 React 调度器集成                                    │  │   │
│  │  │                                                              │  │   │
│  │  │  (d) 创建 BufferedRuntimeExecutor                            │  │   │
│  │  │      - 缓冲 Bundle 加载前的调用                               │  │   │
│  │  │                                                              │  │   │
│  │  │  (e) 设置调试器 (可选)                                        │  │   │
│  │  │                                                              │  │   │
│  │  └──────────────────────────────────────────────────────────────┘  │   │
│  │                                                                     │   │
│  │  ⑤ timerManager->setRuntimeExecutor()                              │   │
│  │                                                                     │   │
│  │  ⑥ initializeRuntime()                                             │   │
│  │         │                                                           │   │
│  │         ▼                                                           │   │
│  │     绑定 console.log, setTimeout, 全局变量...                        │   │
│  │                                                                     │   │
│  │  ⑦ 创建 CallInvokerHolder (TurboModules 用)                        │   │
│  │                                                                     │   │
│  │  ⑧ 包装 RuntimeExecutor/RuntimeScheduler 为 Java 对象              │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

关于JNI函数的注册

前面我们留了一个坑,Kotlin类ReactInstance 中的Native方法initHybrid是如何与C++类JReactInstance 中的initHybrid关联起来的?

根据JNI的规则,总共有两种方式。具体的可以查看谷歌方法提供的JNI 文档。这里好像两种都不像,但我们可以从这个文档知道,当JNI加载动态库时,动态库中可以定义一个全局函数JNI_OnLoad,我们可以在这个全局函数中注册Java/Kotlin的Native方法,将上层的Native方法与具体的C++实现关联起来。而且这个JNI_OnLoad是自动调用的。

我们找到rninstance 库的源码目录,里面刚好包含了一个react-native/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/OnLoad.cpp文件,里面就定义了一个全局函数JNI_OnLoad。到这里似乎一切都没有问题,但这里有一个最大的问题------rninstance 库并没有被独立编译成一个动态库,它是和众多模块一起被最终合并到reactnative 动态库中。所以问题就来了,其他那些被合并的模块中也定义了全局函数JNI_OnLoad,这会直接导致全局函数命名冲突。一个动态库,只能有一个JNI_OnLoad,否则就导致符号冲突了。那么reactnative 动态库中定义的众多JNI_OnLoad函数是怎么回事?

我们先研究一下rninstance 构建脚本react-native/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/CMakeLists.txt

cmake 复制代码
add_library(rninstance
        OBJECT
        ${bridgeless_jni_SRC}
)
# 省略......

target_merge_so(rninstance)

发现这里调用了一个cmake函数target_merge_so,全局搜索找到该函数实现react-native/packages/react-native/ReactAndroid/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake

scss 复制代码
# 如果需要将请求的库与 libreactnative.so 合并,则应调用此函数,例如:
# target_merge_so(react_newarchdefaults)
#
# 此函数将强制包含 jni_lib_merge.h 头文件,该文件负责将 JNI_OnLoad 函数重定义为 JNI_OnLoad_Weak。
function(target_merge_so target_name)
  if(NOT ANDROID)
    return()
  endif()

  target_compile_options(${target_name}
          PRIVATE
            -DORIGINAL_SONAME=\"lib${target_name}.so\"
            -include ${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/jni_lib_merge.h
  )
  target_link_options(${target_name} PRIVATE -Wl,--defsym=JNI_OnLoad=JNI_OnLoad_Weak)
endfunction()

我们从此函数的注释中得到了惊喜!这里通过编译器的一些参数,在rninstance 编译时强制包含了一个头文件jni_lib_merge.h,这个头文件的作用是将原来的JNI_OnLoad函数给重命名了。

cpp 复制代码
#define JNI_OnLoad                                                                                    \
  /* Need to make JNI_OnLoad weak, which requires splitting it into */                                \
  /* a declaration and definition, which is a little risky. */                                        \
  /* Hopefully they didn't use 'extern "C"'. */                                                       \
  JNI_OnLoad_Weak(JavaVM *vm, void *reserved) __attribute__((weak));                                  \
                                                                                                      \
  /* We rename the declared JNI_OnLoad to this so we can call it */                                   \
  /* from either our weak JNI_OnLoad or our merge-friendly init function. */                          \
  static jint pre_merge_original_JNI_OnLoad(JavaVM *vm, void *reserved);                              \
                                                                                                      \
  /* Merge-friendly wrapper for the original JNI_OnLoad, called by JNI. */                            \
  /* Return non-zero to indicate failure. */                                                          \
  static inline jint pre_merge_jni_library_wrapper_for_JNI_OnLoad(JNIEnv *env, jclass clazz)          \
  {                                                                                                   \
    (void)clazz;                                                                                      \
    JNI_MERGE_PRINT("In JNI_OnLoad wrapper for %s", ORIGINAL_SONAME);                                 \
    /* Note: relying on SoLoader's synchronization for thread-safety. */                              \
    static char already_loaded = 0;                                                                   \
    if (already_loaded) {                                                                             \
      return 0;                                                                                       \
    }                                                                                                 \
    already_loaded = 1;                                                                               \
    JavaVM *vm;                                                                                       \
    jint ret = JNI_MERGE_GET_JAVA_VM(env, vm);                                                        \
    if (ret < 0) {                                                                                    \
      /* Exception already thrown. */                                                                 \
      return -1;                                                                                      \
    }                                                                                                 \
    JNI_MERGE_PRINT("Calling original JNI_OnLoad for %s", ORIGINAL_SONAME);                           \
    ret = pre_merge_original_JNI_OnLoad(vm, NULL);                                                    \
    if (!(ret == JNI_VERSION_1_2 || ret == JNI_VERSION_1_4 || ret == JNI_VERSION_1_6)) {              \
      return -1;                                                                                      \
    }                                                                                                 \
    return 0;                                                                                         \
  }                                                                                                   \
                                                                                                      \
  jint JNI_OnLoad_Weak(JavaVM *vm, void *reserved)                                                    \
  {                                                                                                   \
    /* This path will be taken if we're not merged. */                                                \
    /* Just call the original JNI_OnLoad. */                                                          \
    JNI_MERGE_PRINT("Calling original (unmerged) JNI_OnLoad for %s", ORIGINAL_SONAME);                \
    return pre_merge_original_JNI_OnLoad(vm, reserved);                                               \
  }                                                                                                   \
                                                                                                      \
  /* Register our name and wrapper in the proper section. */                                          \
  static struct pre_merge_jni_library pre_merge_jni_library_register_object ATTRIBUTE_RETAIN          \
      __attribute__((__section__("pre_merge_jni_libraries"))) __attribute__((no_sanitize("address"))) \
      __attribute__((__used__)) = {                                                                   \
          .name = ORIGINAL_SONAME,                                                                    \
          .onload_func = pre_merge_jni_library_wrapper_for_JNI_OnLoad,                                \
  };                                                                                                  \
                                                                                                      \
  /* Re-start the JNI_OnLoad prototype to capture the body. */                                        \
  static jint pre_merge_original_JNI_OnLoad

在这个头文件中定义了一个宏JNI_OnLoad 。我们知道C/C++中宏的作用就是在编译前的预处理阶段搞字符串替换。很显然,这里就是将OnLoad.cpp中的JNI_OnLoad函数定义给字符串替换了。替换的内容就是它下面一大串本文。我们要注意这段宏的最后一句static jint pre_merge_original_JNI_OnLoad,它既没有分号也没有括号,显然是替换后与一部分原始内容进行字符串拼接。

我们先看一下OnLoad.cpp的原始内容:

cpp 复制代码
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*unused*/) {
  return facebook::jni::initialize(vm, [] {
    facebook::react::JReactMarker::setLogPerfMarkerIfNeeded();
    facebook::react::JReactInstance::registerNatives();
    facebook::react::JJSTimerExecutor::registerNatives();
    facebook::react::JReactHostInspectorTarget::registerNatives();
  });
}

接下来,我们大致复现一下宏展开之后,完成字符串替换拼接后的样子:

cpp 复制代码
JNIEXPORT jint JNICALL 
  // ===== 宏展开开始 =====
  JNI_OnLoad_Weak(JavaVM *vm, void *reserved) __attribute__((weak));

  static jint pre_merge_original_JNI_OnLoad(JavaVM *vm, void *reserved);

  static inline jint pre_merge_jni_library_wrapper_for_JNI_OnLoad(JNIEnv *env, jclass clazz) {
      // ... 包装函数实现 ...
  }

  jint JNI_OnLoad_Weak(JavaVM *vm, void *reserved) {
      return pre_merge_original_JNI_OnLoad(vm, reserved);
  }

  static struct pre_merge_jni_library pre_merge_jni_library_register_object
      __attribute__((__section__("pre_merge_jni_libraries"))) = {
          .name = "librninstance.so",
          .onload_func = pre_merge_jni_library_wrapper_for_JNI_OnLoad,
      };

  static jint pre_merge_original_JNI_OnLoad   // 宏的最后一行,没有分号
  // ===== 宏展开结束 =====

(JavaVM* vm, void* /*unused*/) {    // 与原始代码的参数列表进行拼接
  return facebook::jni::initialize(vm, [] {
    facebook::react::JReactMarker::setLogPerfMarkerIfNeeded();
    facebook::react::JReactInstance::registerNatives();
    facebook::react::JJSTimerExecutor::registerNatives();
    facebook::react::JReactHostInspectorTarget::registerNatives();
  });
}

这里的宏替换十分巧妙!看到了吗,不仅在函数之前注入了大量内容,最后更是直接将原始函数JNI_OnLoad给重命名为pre_merge_original_JNI_OnLoad,这是一个static修饰的私有函数,并不导出到全局,不存在命名冲突。这里还有一个地方需要注意,就是JNI_OnLoad_Weak(JavaVM *vm, void *reserved) __attribute__((weak))的声明,这里又玩了一个黑科技,将一个函数声明为弱符号。我们知道这个宏是通用的,那么其他模块也会引入,这又会导致全局函数命名冲突,因为每个模块都定义了全局函数JNI_OnLoad_Weak。弱符号声明是一个编译器扩展特性,微软的MSVC编译器就不支持,所以这并不是语言规范,可以说完全是一个黑科技。弱符号的特点就是当存在多个相同的弱符号时不会存在符号冲突,而如果存在一个相同的强符号时,那么强符号自动覆盖弱符号。并且默认的函数定义都是强符号。

所以,这里各个模块的JNI_OnLoad_Weak 定义都是弱符号,在reactnative 库的某个地方,肯定存在一个JNI_OnLoad_Weak 强符号,最终编译时覆盖这些弱符号。这个强符号实现就在react-native/packages/react-native/ReactAndroid/src/main/jni/first-party/jni-lib-merge/jni_lib_merge.c中。

接下来看一下pre_merge_original_JNI_OnLoad函数的实现,具体是facebook::react::JReactInstance::registerNatives()这行,显然这是用于注册Native方法的,我们找到函数的实现:

cpp 复制代码
// JReactInstance.cpp


void JReactInstance::registerNatives() {
  registerHybrid({
      makeNativeMethod("initHybrid", JReactInstance::initHybrid),
      makeNativeMethod(
          "loadJSBundleFromAssets", JReactInstance::loadJSBundleFromAssets),
      makeNativeMethod(
          "loadJSBundleFromFile", JReactInstance::loadJSBundleFromFile),
      makeNativeMethod(
          "getJSCallInvokerHolder", JReactInstance::getJSCallInvokerHolder),
      makeNativeMethod(
          "getNativeMethodCallInvokerHolder",
          JReactInstance::getNativeMethodCallInvokerHolder),
      makeNativeMethod(
          "callFunctionOnModule", JReactInstance::callFunctionOnModule),
     // 省略......
  });
}

现在我们终于找到了JNI Native方法注册的地方,可以看到,上层Kotlin类的 "initHybrid"方法调用,指向了JReactInstance::initHybrid,其他的Native方法也都在此处注册。

现在基本调用流程我们都完成了闭环。但是,如果我们继续深入探究就会发现,在reactnative 库中根本搜不到JNI_OnLoad 方法的声明。这让我一开始也感觉到十分困惑,但我直觉这肯定又是搞了什么黑科技。再次仔细查看SoMerging-utils.cmake构建脚本,果然有所发现:

cmake 复制代码
# 省略......
  target_link_options(${target_name} PRIVATE -Wl,--defsym=JNI_OnLoad=JNI_OnLoad_Weak)

这里又通过编译器参数--defsym=JNI_OnLoad=JNI_OnLoad_Weak 搞了一个符号别名,直接将 JNI_OnLoad 符号定义为 JNI_OnLoad_Weak 的别名,这就相当于JNI_OnLoad_Weak函数等同于JNI_OnLoad

好了,就到处为止。这里面其实还有黑科技,譬如主库reactnative 是如何遍历调用各模块私有的pre_merge_original_JNI_OnLoad函数的?__section__("pre_merge_jni_libraries")又是什么?这些可以自己探究。

相关推荐
行稳方能走远2 小时前
Android java 学习笔记2
android·java
编程之路从0到12 小时前
JSI入门指南
前端·c++·react native
编程之路从0到12 小时前
React Native 之Android端 Bolts库
android·前端·react native
lili-felicity2 小时前
React Native 鸿蒙跨平台开发:Animated 实现鸿蒙端组件的旋转 + 缩放组合动画
react native·react.js·harmonyos
爬山算法2 小时前
Hibernate(38)如何在Hibernate中配置乐观锁?
android·java·hibernate
Mintopia3 小时前
如何结合 AI,为未来社交群体构建「信任桥梁」
人工智能·react native·架构
行稳方能走远3 小时前
Android java 学习笔记 1
android·java
zhimingwen3 小时前
【開發筆記】修復 macOS 上 JADX 啟動崩潰並實現快速啟動
android·macos·反編譯