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")又是什么?这些可以自己探究。

相关推荐
BoomHe2 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农10 小时前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少10 小时前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker10 小时前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋11 小时前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我1 天前
让我们实现一个更好看的内部阴影按钮
android·flutter
阿懂在掘金1 天前
defineModel 是进步还是边界陷阱?双数据源组件的选择逻辑
vue.js·源码阅读
砖厂小工1 天前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心1 天前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心1 天前
Android 17 来了!新特性介绍与适配建议
android·前端