React Native 启动流程 (Android版)

React Native 启动流程 (Android版)

我们从骨架项目MainActivity说起.其继承实现了ReactActivity.
进入MainActivity,先反射MainActivity执行其父类ReactActivity和自己的构造方法。

/** Base Activity for React Native applications. */
public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {

  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    mDelegate = createReactActivityDelegate();
  }

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

然后执行onCreate方法。

class MainActivity : ReactActivity() {
    /**
     * Returns the name of the main component registered from JavaScript. This is used to schedule
     * rendering of the component.
     */
    override fun getMainComponentName(): String = "HelloAndroid"

    /**
     * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
     * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
     */
    override fun createReactActivityDelegate(): ReactActivityDelegate =
        DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}

然后调用DefaultReactActivityDelegate实际上是其父类ReactActivityDelegateonCreate的方法。

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
}

然后调用ReactActivityDelegate的构造方法

public class ReactActivityDelegate {
	public ReactActivityDelegate(
		@Nullable ReactActivity activity, @Nullable String mainComponentName) {
		mActivity = activity;
		mMainComponentName = mainComponentName;
	}
	@DeprecatedInNewArchitecture(message = "Use getReactHost()")
	protected ReactNativeHost getReactNativeHost() {
		return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
	}
	public @Nullable ReactHost getReactHost() {
		return ((ReactApplication) getPlainActivity().getApplication()).getReactHost();
	}
  public void onCreate(Bundle savedInstanceState) {
    Systrace.traceSection(
        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
        "ReactActivityDelegate.onCreate::init",
        () -> {
          String mainComponentName = getMainComponentName(); // 项目的index.js注册的名字,我这边叫HelloWorld
          final Bundle launchOptions = composeLaunchOptions();
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled()) {
            mActivity.getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
          }
          if (ReactNativeFeatureFlags.enableBridgelessArchitecture()) { // 1 true为新架构,false为就架构
            mReactDelegate =
                new ReactDelegate(
                    getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
          } else { // 2
            mReactDelegate =
                new ReactDelegate(
                    getPlainActivity(), // activity
                    getReactNativeHost(), // Application的reactNativeHost
                    mainComponentName,  // HelloWorld
                    launchOptions,
                    isFabricEnabled()) { // fabricEnabled = true
                  @Override
                  protected ReactRootView createRootView() {
                    ReactRootView rootView = ReactActivityDelegate.this.createRootView();
                    if (rootView == null) {
                      rootView = super.createRootView(); // 1
                    }
                    return rootView;
                  }
                };
          }
          if (mainComponentName != null) {
            loadApp(mainComponentName); // 2
          }
        });
  }
   protected void loadApp(String appKey) {
    mReactDelegate.loadApp(appKey);
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  }
}

1处创建了ReactDelegate的匿名对象,并实现了createRootView方法,且调用了ReactDelegatecreateRootView方法。

旧架构

我们来看旧架构。

public class ReactDelegate {

  private final Activity mActivity;
  @Nullable private ReactRootView mReactRootView;

  @Nullable private final String mMainComponentName;

  @Nullable private Bundle mLaunchOptions;

  @Nullable private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;

  @Nullable private ReactNativeHost mReactNativeHost;

  @Nullable private ReactHost mReactHost;

  @Nullable private ReactSurface mReactSurface; // 新架构才需要关心

  private boolean mFabricEnabled = ReactNativeFeatureFlags.enableFabricRenderer();
  
  public ReactDelegate(
      Activity activity,
      ReactNativeHost reactNativeHost,
      @Nullable String appKey,
      @Nullable Bundle launchOptions,
      boolean fabricEnabled) {
    mFabricEnabled = fabricEnabled;
    mActivity = activity;
    mMainComponentName = appKey;
    mLaunchOptions = launchOptions;
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
    mReactNativeHost = reactNativeHost;
  }
  protected ReactRootView createRootView() {
    ReactRootView reactRootView = new ReactRootView(mActivity);
    reactRootView.setIsFabric(isFabricEnabled());
    return reactRootView;
  }
  /**
   * Start the React surface for the given app key.
   *
   * @param appKey The ID of the app to load into the surface.
   */
  public void loadApp(String appKey) {
    // With Bridgeless enabled, create and start the surface
    if (ReactNativeFeatureFlags.enableBridgelessArchitecture()) {
      if (mReactSurface == null) {
        mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);
      }
      mReactSurface.start();
    } else { // 1
      if (mReactRootView != null) {
        throw new IllegalStateException("Cannot loadApp while app is already running.");
      }
      mReactRootView = createRootView();
      mReactRootView.startReactApplication( // 2
          getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
    }
  }

}

createRootView创建了一个ReactRootView对象,ReactActivityDelegate实例对象调用了loadApp然后将ReactRootView设置给了Activity.
2处真正启动了RN运行时环境,
看下ReactNativeHost,这玩意过时了可以使用ReactHost替代,下篇文章分析它。

/**
 * Simple class that holds an instance of {@link ReactInstanceManager}. This can be used in your
 * {@link Application class} (see {@link ReactApplication}), or as a static field.
 */
@DeprecatedInNewArchitecture(
    message =
        "This class will be replaced by com.facebook.react.ReactHost in the new architecture of"
            + " React Native.")
public abstract class ReactNativeHost {

  private final Application mApplication;
  private @Nullable ReactInstanceManager mReactInstanceManager;

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

  /**
   * Get the current {@link ReactInstanceManager} instance, or create one.
   *
   * <p>NOTE: Care must be taken when storing this reference outside of the ReactNativeHost
   * lifecycle. The ReactInstanceManager will be invalidated during {@link #clear()}, and may not be
   * used again afterwards.
   */
  public synchronized ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      ReactMarker.logMarker(ReactMarkerConstants.INIT_REACT_RUNTIME_START);
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
      mReactInstanceManager = createReactInstanceManager();
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
    }
    return mReactInstanceManager;
  }
  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    ReactInstanceManagerBuilder builder = getBaseReactInstanceManagerBuilder();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return builder.build();
  }
  protected ReactInstanceManagerBuilder getBaseReactInstanceManagerBuilder() {
    ReactInstanceManagerBuilder builder =
        ReactInstanceManager.builder()
            .setApplication(mApplication)
            .setJSMainModulePath(getJSMainModuleName())
            .setUseDeveloperSupport(getUseDeveloperSupport())
            .setDevSupportManagerFactory(getDevSupportManagerFactory())
            .setDevLoadingViewManager(getDevLoadingViewManager())
            .setRequireActivity(getShouldRequireActivity())
            .setSurfaceDelegateFactory(getSurfaceDelegateFactory())
            .setJSExceptionHandler(getJSExceptionHandler())
            .setLazyViewManagersEnabled(getLazyViewManagersEnabled())
            .setRedBoxHandler(getRedBoxHandler())
            .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
            .setUIManagerProvider(getUIManagerProvider())
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
            .setReactPackageTurboModuleManagerDelegateBuilder(
                getReactPackageTurboModuleManagerDelegateBuilder())
            .setJSEngineResolutionAlgorithm(getJSEngineResolutionAlgorithm())
            .setChoreographerProvider(getChoreographerProvider())
            .setPausedInDebuggerOverlayManager(getPausedInDebuggerOverlayManager());

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

    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    return builder;
  }

可以看到getJSBundleFile优先于getBundleAssetName.

看下 mReactRootView.startReactApplication

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

 public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName) {
    startReactApplication(reactInstanceManager, moduleName, null);
  }

  /**
   * Schedule rendering of the react component rendered by the JS application from the given JS
   * module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the JS
   * context of that manager. Extra parameter {@param initialProperties} can be used to pass initial
   * properties for the react component.
   */
  @ThreadConfined(UI)
  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
    try {
      UiThreadUtil.assertOnUiThread();

      // TODO(6788889): Use POJO instead of bundle here, apparently we can't just use WritableMap
      // here as it may be deallocated in native after passing via JNI bridge, but we want to reuse
      // it in the case of re-creating the catalyst instance
      Assertions.assertCondition(
          mReactInstanceManager == null,
          "This root view has already been attached to a catalyst instance manager");

      mReactInstanceManager = reactInstanceManager;
      mJSModuleName = moduleName;
      mAppProperties = initialProperties;

      mReactInstanceManager.createReactContextInBackground(); // 1
      // if in this experiment, we initialize the root earlier in startReactApplication
      // instead of waiting for the initial measure
      if (ReactNativeFeatureFlags.enableEagerRootViewAttachment()) {
        if (!mWasMeasured) {
          // Ideally, those values will be used by default, but we only update them here to scope
          // this change to `enableEagerRootViewAttachment` experiment.
          setSurfaceConstraintsToScreenSize();
        }
        attachToReactInstanceManager();
      }
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

查看1处的源码

@ThreadSafe
@StableReactNativeAPI
public class ReactInstanceManager {

  private static final String TAG = ReactInstanceManager.class.getSimpleName();
  
  @ThreadConfined(UI)
  public void createReactContextInBackground() {
    FLog.d(TAG, "ReactInstanceManager.createReactContextInBackground()");
    UiThreadUtil
        .assertOnUiThread(); // Assert before setting mHasStartedCreatingInitialContext = true
    if (!mHasStartedCreatingInitialContext) {
      mHasStartedCreatingInitialContext = true;
      recreateReactContextInBackgroundInner(); // 1
    }
  }

  /**
   * Recreate the react application and context. This should be called if configuration has changed
   * or the developer has requested the app to be reloaded. It should only be called after an
   * initial call to createReactContextInBackground.
   *
   * <p>Called from UI thread.
   */
  @ThreadConfined(UI)
  public void recreateReactContextInBackground() {
    Assertions.assertCondition(
        mHasStartedCreatingInitialContext,
        "recreateReactContextInBackground should only be called after the initial "
            + "createReactContextInBackground call.");
    recreateReactContextInBackgroundInner();
  }

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

    if (mUseDeveloperSupport && mJSMainModulePath != null) { // debug模式
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
      if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
        if (mBundleLoader == null) {
          mDevSupportManager.handleReloadJS();
        } else {
          mDevSupportManager.isPackagerRunning(
              new PackagerStatusCallback() {
                @Override
                public void onPackagerStatusFetched(final boolean packagerIsRunning) {
                  UiThreadUtil.runOnUiThread(
                      () -> {
                        // ReactInstanceManager is no longer valid, ignore callback
                        if (mInstanceManagerInvalidated) {
                          return;
                        }

                        if (packagerIsRunning) {
                          mDevSupportManager.handleReloadJS();
                        } else if (mDevSupportManager.hasUpToDateJSBundleInCache()
                            && !devSettings.isRemoteJSDebugEnabled()
                            && !mUseFallbackBundle) {
                          // If there is a up-to-date bundle downloaded from server,
                          // with remote JS debugging disabled, always use that.
                          onJSBundleLoadedFromServer();
                        } else {
                          // If dev server is down, disable the remote JS debugging.
                          devSettings.setRemoteJSDebugEnabled(false);
                          recreateReactContextInBackgroundFromBundleLoader();
                        }
                      });
                }
              });
        }
        return;
      }
    }

    recreateReactContextInBackgroundFromBundleLoader(); // 2
  }

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader");
    recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader); // 3
  }
  @ThreadConfined(UI)
  private void recreateReactContextInBackground(
      JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
    FLog.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackground()");
    UiThreadUtil.assertOnUiThread();

    final ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    if (mCreateReactContextThread == null) {
      runCreateReactContextOnNewThread(initParams); // 4
    } else {
      mPendingReactContextInitParams = initParams;
    }
  }
      @ThreadConfined("UI")
    private void runCreateReactContextOnNewThread(ReactContextInitParams initParams) {
        FLog.d("ReactNative", "ReactInstanceManager.runCreateReactContextOnNewThread()");
        UiThreadUtil.assertOnUiThread();
        Assertions.assertCondition(!this.mInstanceManagerInvalidated, "Cannot create a new React context on an invalidated ReactInstanceManager");
        ReactMarker.logMarker(ReactMarkerConstants.REACT_BRIDGE_LOADING_START);
        synchronized(this.mAttachedReactRoots) {
            synchronized(this.mReactContextLock) {
                if (this.mCurrentReactContext != null) {
                    this.tearDownReactContext(this.mCurrentReactContext); // 旧 Context 清理
                    this.mCurrentReactContext = null;
                }
            }
        }

        this.mCreateReactContextThread = new Thread((ThreadGroup)null, () -> {
            ReactMarker.logMarker(ReactMarkerConstants.REACT_CONTEXT_THREAD_END);
            synchronized(this.mHasStartedDestroying) {
                while(this.mHasStartedDestroying) {
                    try {
                        this.mHasStartedDestroying.wait();
                    } catch (InterruptedException var7) {
                    }
                }
            }

            this.mHasStartedCreatingInitialContext = true;

            ReactApplicationContext reactApplicationContext;
            try {
                Process.setThreadPriority(-4);
                ReactMarker.logMarker(ReactMarkerConstants.VM_INIT);
                reactApplicationContext = this.createReactContext(initParams.getJsExecutorFactory().create(), initParams.getJsBundleLoader()); // 1
            } catch (Exception e) {
                this.mHasStartedCreatingInitialContext = false;
                this.mCreateReactContextThread = null;
                this.mDevSupportManager.handleException(e);
                return;
            }

            try {
                this.mCreateReactContextThread = null;
                ReactMarker.logMarker(ReactMarkerConstants.PRE_SETUP_REACT_CONTEXT_START);
                Runnable maybeRecreateReactContextRunnable = () -> {
                    if (this.mPendingReactContextInitParams != null) {
                        this.runCreateReactContextOnNewThread(this.mPendingReactContextInitParams); // 2
                        this.mPendingReactContextInitParams = null;
                    }

                };
                Runnable setupReactContextRunnable = () -> {
                    try {
                        this.setupReactContext(reactApplicationContext); // 3
                    } catch (Exception e) {
                        this.mDevSupportManager.handleException(e);
                    }

                };
                reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable); 
                UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
            } catch (Exception e) {
                this.mDevSupportManager.handleException(e);
            }

        }, "create_react_context");
        ReactMarker.logMarker(ReactMarkerConstants.REACT_CONTEXT_THREAD_START);
        this.mCreateReactContextThread.start();
    }
/**
   * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
   */
  private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
    FLog.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
    ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());

    final BridgeReactContext reactContext = new BridgeReactContext(mApplicationContext);

    JSExceptionHandler exceptionHandler =
        mJSExceptionHandler != null ? mJSExceptionHandler : mDevSupportManager;
    reactContext.setJSExceptionHandler(exceptionHandler);

    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages);

    CatalystInstanceImpl.Builder catalystInstanceBuilder =
        new CatalystInstanceImpl.Builder()
            .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            .setJSBundleLoader(jsBundleLoader)
            .setJSExceptionHandler(exceptionHandler)
            .setInspectorTarget(getOrCreateInspectorTarget());

    ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
    // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
    final CatalystInstance catalystInstance;
    try {
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
    }

    reactContext.initializeWithInstance(catalystInstance);

    // On Old Architecture, we need to initialize the Native Runtime Scheduler so that
    // the `nativeRuntimeScheduler` object is registered on JS.
    // On New Architecture, this is normally triggered by instantiate a TurboModuleManager.
    // Here we invoke getRuntimeScheduler() to trigger the creation of it regardless of the
    // architecture so it will always be there.
    catalystInstance.getRuntimeScheduler();

    if (ReactNativeFeatureFlags.useTurboModules() && mTMMDelegateBuilder != null) {
      TurboModuleManagerDelegate tmmDelegate =
          mTMMDelegateBuilder
              .setPackages(mPackages)
              .setReactApplicationContext(reactContext)
              .build();

      TurboModuleManager turboModuleManager =
          new TurboModuleManager(
              catalystInstance.getRuntimeExecutor(),
              tmmDelegate,
              catalystInstance.getJSCallInvokerHolder(),
              catalystInstance.getNativeMethodCallInvokerHolder());

      catalystInstance.setTurboModuleRegistry(turboModuleManager);

      // Eagerly initialize TurboModules
      for (String moduleName : turboModuleManager.getEagerInitModuleNames()) {
        turboModuleManager.getModule(moduleName);
      }
    }

    if (mUIManagerProvider != null) {
      UIManager uiManager = mUIManagerProvider.createUIManager(reactContext);
      if (uiManager != null) {
        catalystInstance.setFabricUIManager(uiManager);

        // Initialize the UIManager
        uiManager.initialize();
        catalystInstance.setFabricUIManager(uiManager);
      }
    }
    if (mBridgeIdleDebugListener != null) {
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    }
    if (BuildConfig.ENABLE_PERFETTO
        || Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
      catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
    }

    ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
    catalystInstance.runJSBundle(); // 1
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    return reactContext;
  }

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

private fun getDefaultJSExecutorFactory(
	appName: String,
	deviceName: String,
	applicationContext: Context,
): JavaScriptExecutorFactory? {
	ReactInstanceManager.initializeSoLoaderIfNecessary(applicationContext)
		// Hermes has been enabled by default in OSS since React Native 0.70.
		try {
			HermesExecutor.loadLibrary()
				return HermesExecutorFactory()
			} catch (error: UnsatisfiedLinkError) {
			FLog.e(
				TAG,
				"Unable to load Hermes. Your application is not built correctly and will fail to execute",
			)
				return null
			}
}

facebook/react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.kt

/** A class that stores JS bundle information and allows a [JSBundleLoaderDelegate]. */
public abstract class JSBundleLoader {

  /** Loads the script, returning the URL of the source it loaded. */
  public abstract fun loadScript(delegate: JSBundleLoaderDelegate): String

  public companion object {
    /**
     * This loader is recommended one for release version of your app. In that case local JS
     * executor should be used. JS bundle will be read from assets in native code to save on passing
     * large strings from java to native memory.
     */
    @JvmStatic
    public fun createAssetLoader(
        context: Context,
        assetUrl: String,
        loadSynchronously: Boolean,
    ): JSBundleLoader =
        object : JSBundleLoader() {
          override fun loadScript(delegate: JSBundleLoaderDelegate): String {
            delegate.loadScriptFromAssets(context.assets, assetUrl, loadSynchronously) // 1
            return assetUrl
          }
        }

delegate实际上就是CatalystInstanceImpl
createReactContext方法就会创建CatalystInstanceImpl,然后加载jsBundle.
wdf,这玩意挺复杂的,别着急慢慢来, CatalystInstanceImpl → JNI → Hermes/JSC ,hahaha

CatalystInstanceImpl

@DoNotStrip
public class CatalystInstanceImpl implements CatalystInstance {
  static {
    ReactBridge.staticInit(); // 1
  }
   private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      JSExceptionHandler jSExceptionHandler,
      @Nullable ReactInstanceManagerInspectorTarget inspectorTarget) {
    FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl");

    mHybridData = initHybrid();

    mReactQueueConfiguration =
        ReactQueueConfigurationImpl.create(
            reactQueueConfigurationSpec, new NativeExceptionHandler());
    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
    mNativeModuleRegistry = nativeModuleRegistry;
    mJSModuleRegistry = new JavaScriptModuleRegistry();
    mJSBundleLoader = jsBundleLoader;
    mJSExceptionHandler = jSExceptionHandler;
    mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
    mTraceListener = new JSProfilerTraceListener(this);
    mInspectorTarget = inspectorTarget;
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "initializeCxxBridge");

    initializeBridge(
        new InstanceCallback(this),
        jsExecutor,
        mReactQueueConfiguration.getJSQueueThread(),
        mNativeModulesQueueThread,
        mNativeModuleRegistry.getJavaModules(this),
        mNativeModuleRegistry.getCxxModules(),
        mInspectorTarget);
    FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
  }
   @Override
  public void runJSBundle() {
    FLog.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()");
    Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
    // incrementPendingJSCalls();
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);

    synchronized (mJSCallsPendingInitLock) {

      // Loading the bundle is queued on the JS thread, but may not have
      // run yet.  It's safe to set this here, though, since any work it
      // gates will be queued on the JS thread behind the load.
      mAcceptCalls = true;

      for (PendingJSCall function : mJSCallsPendingInit) {
        function.call(this);
      }
      mJSCallsPendingInit.clear();
      mJSBundleHasLoaded = true;
    }

    // This is registered after JS starts since it makes a JS call
    Systrace.registerListener(mTraceListener);
  }
}

代码1处进行JNI函数注册.
packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp

extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
#ifdef WITH_XPLATINIT
  return facebook::xplat::initialize(vm, [] {
#else
  return jni::initialize(vm, [] {
#endif
#if WITH_GLOGINIT
    gloginit::initialize();
    FLAGS_minloglevel = 0;
#endif

    ProxyJavaScriptExecutorHolder::registerNatives();
    CatalystInstanceImpl::registerNatives();
    CxxModuleWrapperBase::registerNatives();
    JCxxCallbackImpl::registerNatives();
    NativeArray::registerNatives();
    ReadableNativeArray::registerNatives();
    WritableNativeArray::registerNatives();
    NativeMap::registerNatives();
    ReadableNativeMap::registerNatives();
    WritableNativeMap::registerNatives();
    JDynamicNative::registerNatives();
    JReactMarker::registerNatives();
    JInspector::registerNatives();
    ReactInstanceManagerInspectorTarget::registerNatives();
    InspectorNetworkRequestListener::registerNatives();
  });
}
posted @ 2025-10-21 22:32  爱情丶眨眼而去  阅读(1)  评论(0)    收藏  举报