React Native 启动流程 (Android版)
我们从骨架项目MainActivity
说起.其继承实现了ReactActivity
.
进入MainActivity
,先反射MainActivity
执行其父类ReactActivity
和自己的构造方法。
/** Base Activity for React Native applications. */
public abstract class ReactActivity extends AppCompatActivityimplements DefaultHardwareBackBtnHandler, PermissionAwareActivity {private final ReactActivityDelegate mDelegate;protected ReactActivity() {mDelegate = createReactActivityDelegate();}@Overrideprotected 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
实际上是其父类ReactActivityDelegate
的onCreate
的方法。
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注册的名字,我这边叫HelloWorldfinal 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 { // 2mReactDelegate =new ReactDelegate(getPlainActivity(), // activitygetReactNativeHost(), // Application的reactNativeHostmainComponentName, // HelloWorldlaunchOptions,isFabricEnabled()) { // fabricEnabled = true@Overrideprotected 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`方法,且调用了`ReactDelegate`的`createRootView`方法。
旧架构
我们来看旧架构。
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 surfaceif (ReactNativeFeatureFlags.enableBridgelessArchitecture()) {if (mReactSurface == null) {mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);}mReactSurface.start();} else { // 1if (mReactRootView != null) {throw new IllegalStateException("Cannot loadApp while app is already running.");}mReactRootView = createRootView();mReactRootView.startReactApplication( // 2getReactNativeHost().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 instanceAssertions.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 measureif (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 = trueif (!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() {@Overridepublic void onPackagerStatusFetched(final boolean packagerIsRunning) {UiThreadUtil.runOnUiThread(() -> {// ReactInstanceManager is no longer valid, ignore callbackif (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); // 2this.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();}
createReactContext
方法就会创建CatalystInstanceImpl
wdf,这玩意挺复杂的,别着急慢慢来, CatalystInstanceImpl → JNI → Hermes/JSC
,hahaha