从Android的角度窥探ReactNative的原理
1 简介
1.1 ReactNative的跨平台
ReactNative是一种跨平台开发App的技术,跨平台使得用一套代码就能在多个平台发布,节省了人力和各种资源。
怎么实现跨平台呢?回想两个我们已经掌握的知识你就能明白了。
1 回想一下当我们遇到大量重复性代码的时候会怎么做?是不是会考虑将有共性的东西抽象出来,同一个App虽然在Android和IOS的两个平台上代码实现上完全不同,但其实视图、交互以及业务逻辑这些都是具有共性的,是可以抽象出来的。
2 java也是跨平台的,我们回想一下java一次编译,到处运行的原理:先将java编译成字节码,然后在不同平台,jvm使用其内部相应的解释器解释成机器码(每个平台解释出来的机器码内容是不同的,看完下一段话后自己思考一下对应了什么!)。
因此我们可以这样实现跨平台:将视图、交互以及业务逻辑抽象出来,然后使用同一套代码(RN选择了Js)来实现,最后再使用不同的解释器,解释给各个平台。
1.2 简析RN工程的架构
本质上RN是一个第三方框架,它提供了执行js代码的能力,同时搭建了一套js和原生(Android和IOS)的通信体系。原生使用这个框架后,就可以将一部分功能的实现和逻辑的处理转移到js(本来实现这部分的功能和逻辑需要两套代码,即Android和IOS各自实现一遍,现在使用js一套代码就能实现)。由此可见尽可能的将更多的功能用js来实现就能节省更多的代码,但实际上js能力是十分有限的,比如js没有绘制引擎,因此我们用js写的UI本质上,最终是js告知原生UI的信息(位置,大小,颜色等),由原生负责真正的绘制。
可以看出js更多的是一种逻辑处理,而原生负责真正的实现,核型工作原理就是js和原生通过RN搭建的通讯体系进行协作和通讯。
具体native和js是怎么协作和通讯的呢?从使用的角度,我们只需要知道,js如何调用native和native如何调用js。要深入探究原理的话,由于两者的底层通讯是用c++实现的,就变成了js调用c++,c++调用原生,以及原生调用c++,c++调用js。由于我暂时不会c++,接下来的分析涉及到的RN源码只限于java和js。
2 RN的启动流程
RN项目是原生项目的扩展(我们的js代码被打包成一个bundle文件,作为资源文件放在原生项目中),本质上还是原生项目。因此我们从Android项目的角度入手,结合源码进行分析。
2.1 创建Application
Android项目启动的第一步当然是创建Application对象,来看看RN为我们提供的ReactApplication。
public interface ReactApplication { ReactNativeHost getReactNativeHost(); } 复制代码
ReactApplication是一个接口,提供一个返回ReactNativeHost对象的方法。
再来看看RN项目默认创建的Application。
public class MainApplication extends Application implements ReactApplication { // 实现ReactApplication接口 private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {// 创建一个final的ReactNativeHost对象 @Override // 配置是否是dev(开发)模式,是的话会开启一些调试,同时导致加载jsBundle的方式不一样。 public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { // 配置要加载的ReactPackage @SuppressWarnings("UnnecessaryLocalVariable") List<ReactPackage> packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: // packages.add(new MyReactNativePackage()); return packages; } @Override protected String getJSMainModuleName() { // 配置js的入口模块名 return "index"; } }; @Override public ReactNativeHost getReactNativeHost() {// 提供一个返回ReactNativeHost对象的方法 return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); // SoLoader是so文件加载库,用来加载C/C++底层库 SoLoader.init(this, /* native exopackage */ false); // 初始化Flipper。Flipper是facebook推出的用于 debug ios、Android、React Native 应用的工具。 initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } /** * Loads Flipper in React Native templates. Call this in the onCreate method with something like * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); * * @param context * @param reactInstanceManager */ private static void initializeFlipper( Context context, ReactInstanceManager reactInstanceManager) { if (BuildConfig.DEBUG) { try { /* We use reflection here to pick up the class that initializes Flipper, since Flipper library is not available in release mode */ Class<?> aClass = Class.forName("com.awesomeproject.ReactNativeFlipper"); aClass .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) .invoke(null, context, reactInstanceManager); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } 复制代码
类似我们平时提供一个全局的ApplicaitionContext一样,这里提供了一个全局的ReactNativeHost对象。ReactNativeHost是一个抽象类,我们可以通过重写它的方法(getUseDeveloperSupport和getPackages没有默认实现,必须重写)来实现一些关于RN的全局配置。一个ReactPackage可以配置多个ViewManager、NativeModule,这部分是关于js调用原生的使用,详见ReactNative官方文档。
2.2 创建Activity
下一步就是创建MainActivity了,来看看RN项目默认创建的MainActivity。
public class MainActivity extends ReactActivity { /** * Returns the name of the main component registered from JavaScript. This is used to schedule * rendering of the component. */ @Override protected String getMainComponentName() {// 返回js注册的主组件名。后续存到ReactRootView的mJSModuleName属性。 return "AwesomeProject"; } } 复制代码
继承了ReactActivity,重写了getMainComponentName方法。
Activity创建完就该走生命周期流程了,我们的onCreate方法呢?让我们进入ReactActivity一起看看。
2.2.1 ReactActivity
public abstract class ReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { private final ReactActivityDelegate mDelegate; // 初始化时创建ReactActivityDelegate代理对象 protected ReactActivity() { mDelegate = createReactActivityDelegate(); } protected @Nullable String getMainComponentName() { return null; } // 创建ReactActivityDelegate时,为其绑定当前Activity和mainComponentName。 protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDelegate.onCreate(savedInstanceState); } ... // 其他委派方法 } 复制代码
ReactActivity初始化时创建ReactActivityDelegate代理对象,并将自己的生命周期、硬件返回按钮事件和权限相关的回调,全部委派给了ReactActivityDelegate对象。因此ReactActivity的onCreate方法就进入到了ReactActivityDelegate的onCreate方法。
2.2.2 ReactActivityDelegate
public class ReactActivityDelegate { private final @Nullable Activity mActivity; private final @Nullable String mMainComponentName; private @Nullable PermissionListener mPermissionListener; private @Nullable Callback mPermissionsCallback; private ReactDelegate mReactDelegate; @Deprecated public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) { mActivity = activity; mMainComponentName = mainComponentName; } // 初始化绑定了宿主ReactActivity和js主组件名 public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) { mActivity = activity; mMainComponentName = mainComponentName; } protected @Nullable Bundle getLaunchOptions() { return null; } protected ReactRootView createRootView() {// 默认创建ReactRootView的方法,可以重写此方法来自定义创建方法。 return new ReactRootView(getContext()); } protected ReactNativeHost getReactNativeHost() { return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost(); } public ReactInstanceManager getReactInstanceManager() { return mReactDelegate.getReactInstanceManager(); } public String getMainComponentName() { return mMainComponentName; } protected void onCreate(Bundle savedInstanceState) { String mainComponentName = getMainComponentName(); // 创建ReactDelegate对象 mReactDelegate = new ReactDelegate( getPlainActivity(), // 宿主Activity getReactNativeHost(), // 全局的ReactNativeHost对象 mainComponentName, // js入口组件 getLaunchOptions()) // Bundle对象,用来存放传递给js的初始化参数,默认为null { @Override protected ReactRootView createRootView() { // 配置初始化ReactRootView的方法, return ReactActivityDelegate.this.createRootView(); } }; // 之前配置的mainComponentName不为空的话调用loadApp方法 if (mMainComponentName != null) { loadApp(mainComponentName);// 传入mainComponentName } } protected void loadApp(String appKey) { // 加载js代码的入口 mReactDelegate.loadApp(appKey); // 为宿主Activity绑定contentView(熟悉吗OvO) getPlainActivity().setContentView(mReactDelegate.getReactRootView()); } ... protected Context getContext() { return Assertions.assertNotNull(mActivity); } protected Activity getPlainActivity() { return ((Activity) getContext()); } } 复制代码
在onCreate方法中首先创建ReactDelegate对象,然后调用了ReactDelegate的loadApp方法,最后在调用setContentView方法传入了一个ReactRootView。**本质上比起普通的Activity,只是setContentView的内容不一样了。**前面说过js负责告诉原生视图长啥样,原生负责渲染,ReactRootView就是js给原生的答案,让我们看看ReactDelegate的loadApp方法。
2.2.3 ReactDelegate
public class ReactDelegate { private final Activity mActivity; private ReactRootView mReactRootView; @Nullable private final String mMainComponentName; @Nullable private Bundle mLaunchOptions; @Nullable private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private ReactNativeHost mReactNativeHost; public ReactDelegate( Activity activity, ReactNativeHost reactNativeHost, @Nullable String appKey, @Nullable Bundle launchOptions) { mActivity = activity; mMainComponentName = appKey; mLaunchOptions = launchOptions; mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); mReactNativeHost = reactNativeHost; } ... public void loadApp() { loadApp(mMainComponentName); } public void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView();// 创建一个ReactRootView对象 mReactRootView.startReactApplication( // 然后调用startReactApplication方法 getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions); } public ReactRootView getReactRootView() { return mReactRootView; } // ReactActivityDelegate创建ReactDelegate时重写了此方法 protected ReactRootView createRootView() { return new ReactRootView(mActivity); } ... private ReactNativeHost getReactNativeHost() { return mReactNativeHost; } public ReactInstanceManager getReactInstanceManager() { return getReactNativeHost().getReactInstanceManager(); } } 复制代码
loadApp方法中首先创建一个ReactRootView对象,然后调用了ReactRootView对象的startReactApplication方法。
2.2.4 ReactRootView
ReactRootView的创建非常简单,我们的重点是startReactApplication方法:
public class ReactRootView extends FrameLayout implements RootView, ReactRoot { ... public ReactRootView(Context context) { super(context); init(); } public ReactRootView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ReactRootView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { setClipChildren(false); } } 复制代码
ReactRootView#startReactApplication:
mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), // 获取ReactInstanceManager对象 appKey, // mainComponentName mLaunchOptions // 前面有提到,Bundle对象,存放传递给主组件的参数,默认为null ); 复制代码
首先是调用ReactNativeHost对象的getReactInstanceManager()获取ReactInstanceManager对象。
2.2.5 ReactInstanceManager
ReactNativeHost.java
public abstract class ReactNativeHost { private final Application mApplication; // 全局唯一的ReactNativeHost管理了一个mReactInstanceManager对象,因此mReactInstanceManager也是全局单例。 private @Nullable ReactInstanceManager mReactInstanceManager; protected ReactNativeHost(Application application) { mApplication = application; } public ReactInstanceManager getReactInstanceManager() { if (mReactInstanceManager == null) { // 没有的话创建 ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START); // 调用createReactInstanceManager方法创建一个ReactInstanceManager对象 mReactInstanceManager = createReactInstanceManager(); ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END); } return mReactInstanceManager;// 有的话直接返回 } // 创建ReactInstanceManager对象的方法 protected ReactInstanceManager createReactInstanceManager() { ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START); ReactInstanceManagerBuilder builder = ReactInstanceManager.builder() .setApplication(mApplication)// 应用上下文 .setJSMainModulePath(getJSMainModuleName())// debug模式下jsBundle名 .setUseDeveloperSupport(getUseDeveloperSupport())// 是否开启dev模式 .setDevSupportManagerFactory(getDevSupportManagerFactory()) .setRequireActivity(getShouldRequireActivity()) .setSurfaceDelegateFactory(getSurfaceDelegateFactory()) .setRedBoxHandler(getRedBoxHandler()) .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory()) .setUIImplementationProvider(getUIImplementationProvider()) .setJSIModulesPackage(getJSIModulePackage()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE) .setReactPackageTurboModuleManagerDelegateBuilder( getReactPackageTurboModuleManagerDelegateBuilder()); for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); } // 配置jsBundle的加载路径(后续加载的时候用到) String jsBundleFile = getJSBundleFile(); if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile); } else { builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())); } // 真正创建ReactInstanceManager的入口 ReactInstanceManager reactInstanceManager = builder.build(); ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END); return reactInstanceManager; } // dev模式下从服务器传过来的jsBundle的默认名 protected String getJSMainModuleName() { return "index.android"; } // 通过配置jsBundle在资源文件夹(assets文件夹)下的文件名来加载jsBundle protected @Nullable String getBundleAssetName() { return "index.android.bundle"; } // 通过配置jsBundle的文件路径来加载jsBundle,默认为null protected @Nullable String getJSBundleFile() { return null; } public abstract boolean getUseDeveloperSupport( protected abstract List<ReactPackage> getPackages(); ... // 其他默认配置,大部分都是null } 复制代码
ReactNativeHost将核心任务统统交给了ReactInstanceManager,初始化ReactInstanceManager时,也初始化了很多关于RN的默认配置,包括是否开启debug模式,后续加载jsBundle的方式,ReactPackage等等,我们可以重写初始化ReactNativeHost的方法来修改默认配置。当然真正的创建在ReactInstanceManagerBuilder的build方法中。
ReactInstanceManagerBuilder.java#build
public ReactInstanceManager build() { //一些断言 ... if (mUIImplementationProvider == null) { // create default UIImplementationProvider if the provided one is null. mUIImplementationProvider = new UIImplementationProvider(); } // We use the name of the device and the app for debugging & metrics //noinspection ConstantConditions String appName = mApplication.getPackageName(); String deviceName = getFriendlyDeviceName(); return new ReactInstanceManager( mApplication, mCurrentActivity, mDefaultHardwareBackBtnHandler, mJavaScriptExecutorFactory == null ? getDefaultJSExecutorFactory(appName, deviceName, mApplication.getApplicationContext()) : mJavaScriptExecutorFactory, //创建JSBundleLoader对象来存储关于加载jsBundle的方式和路径,其内部后续再来看 (mJSBundleLoader == null && mJSBundleAssetUrl != null) ? JSBundleLoader.createAssetLoader( mApplication, mJSBundleAssetUrl, false /*Asynchronous*/) : mJSBundleLoader, mJSMainModulePath, mPackages, mUseDeveloperSupport, mDevSupportManagerFactory == null ? new DefaultDevSupportManagerFactory() : mDevSupportManagerFactory, mRequireActivity, mBridgeIdleDebugListener, Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), mUIImplementationProvider, mNativeModuleCallExceptionHandler, mRedBoxHandler, mLazyViewManagersEnabled, mDevBundleDownloadListener, mMinNumShakes, mMinTimeLeftInFrameForNonBatchedOperationMs, mJSIModulesPackage, mCustomPackagerCommandHandlers, mTMMDelegateBuilder, mSurfaceDelegateFactory ); } 复制代码
ReactInstanceManager中的一些配置,在后续使用到了再来分析,我们接着看startApplication方法。
ReactRootView.java#startApplication
public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties) { startReactApplication(reactInstanceManager, moduleName, initialProperties, null); } @ThreadConfined(UI) public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties, @Nullable String initialUITemplate) { Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication"); try { UiThreadUtil.assertOnUiThread(); //断言,确保mReactInstanceManager不为空 Assertions.assertCondition( mReactInstanceManager == null, "This root view has already been attached to a catalyst instance manager"); mReactInstanceManager = reactInstanceManager; // 前面一路传进来的参数改个名而已 // js主组件名,ReactActivity的getJSMainModuleName,ReactActivityDelegate的mainComponentName。 mJSModuleName = moduleName; // 传递给js主组件的初始化数据,默认为null,ReactActivityDelegate的mLaunchOptions mAppProperties = initialProperties; mInitialUITemplate = initialUITemplate; // 创建ReactContext mReactInstanceManager.createReactContextInBackground(); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } 复制代码
核心是调用了mReactInstanceManager的createReactContextInBackground()方法来创建ReactContext,ReactContext和其他Context一样继承ContextWrapper,是ReactNative的上下文,我们通过ReactContext来访问RN的各种核心实现类。
2.3 创建ReactContext
ReactInstanceManager.java#createReactContextInBackground
@ThreadConfined(UI) public void createReactContextInBackground() { FLog.d(TAG, "ReactInstanceManager.createReactContextInBackground()"); UiThreadUtil.assertOnUiThread(); if (!mHasStartedCreatingInitialContext) { mHasStartedCreatingInitialContext = true; // 如果没有创建过ReactContext,就调用recreateReactContextInBackgroundInner方法创建 recreateReactContextInBackgroundInner(); } } //重新创建react的application和context,此方法用于配置发生变化或者我们主动要求重启RN应用时。 @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(); // 如果是dev环境且mJSMainModulePath不为空,则从metro服务器加载jsBundle if (mUseDeveloperSupport && mJSMainModulePath != null) { final DeveloperSettings devSettings = mDevSupportManager.getDevSettings(); if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) { if (mBundleLoader == null) { // 从metro服务器加载jsBundle mDevSupportManager.handleReloadJS(); } else { mDevSupportManager.isPackagerRunning( new PackagerStatusCallback() { @Override public void onPackagerStatusFetched(final boolean packagerIsRunning) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { if (packagerIsRunning) { mDevSupportManager.handleReloadJS(); } else if (mDevSupportManager.hasUpToDateJSBundleInCache() && !devSettings.isRemoteJSDebugEnabled() && !mUseFallbackBundle) { // 在禁用远程JS调试的情况下,使用服务器之前下载的最新的jsBundle onJSBundleLoadedFromServer(); } else { // 如果dev服务器关闭了,则关闭远程JS调试。 devSettings.setRemoteJSDebugEnabled(false); recreateReactContextInBackgroundFromBundleLoader(); } } }); } }); } return; } } // 非dev模式下调用 recreateReactContextInBackgroundFromBundleLoader(); } @ThreadConfined(UI) private void recreateReactContextInBackgroundFromBundleLoader() { FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()"); PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader"); // mJavaScriptExecutorFactory默认为空,mBundleLoader保存了加载jsBundle的方式和路径,是前面创建ReactInstanceManager时,根据我们的配置创建的。 recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader); } @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) { // 如果当前没有创建ReactContext的线程,则创建一个新线程来创建ReactCotext。 runCreateReactContextOnNewThread(initParams); } else { mPendingReactContextInitParams = initParams; } } @ThreadConfined(UI) private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) { ... mCreateReactContextThread = new Thread( null, new Runnable() { @Override public void run() { ... mHasStartedCreatingInitialContext = true; try { Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); ReactMarker.logMarker(VM_INIT); // 创建ReactContext的入口 // ReactApplicationContext继承ReactContext,简单的包装了一下 final ReactApplicationContext reactApplicationContext = createReactContext( initParams.getJsExecutorFactory().create(), initParams.getJsBundleLoader()); ... // 创建一个Runnable,封装了成功创建ReactContext后要做的事。 Runnable setupReactContextRunnable = new Runnable() { @Override public void run() { try { setupReactContext(reactApplicationContext); } catch (Exception e) { // TODO T62192299: remove this after investigation FLog.e( ReactConstants.TAG, "ReactInstanceManager caught exception in setupReactContext", e); mDevSupportManager.handleException(e); } } }; // 在NativeModule线程中,执行setupReactContextRunnable reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable); UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable); } catch (Exception e) { mDevSupportManager.handleException(e); } } }, "create_react_context"); mCreateReactContextThread.start(); } 复制代码
可以看到最终是调用了createReactContext方法,然后创建一个Runnable,封装了成功创建ReactContext后要做的事。我们来看看创建ReactContext的核心方法。
ReactInstanceManager.java#createReactContext
private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { ... // 创建ReactApplicationContext对象 ReactApplicationContext reactContext = new ReactApplicationContext(this.mApplicationContext); // mPackages就是我们之前在ReactNativeHost配置的ReactPackage列表 // processPackages方法将ReactPackage列表封装成NativeModule注册表(NativeModuleRegistry对象) NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false); //创建CatalystInstanceImpl.Builder对象 CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry)// 设置NativeModule注册表 .setJSBundleLoader(jsBundleLoader)// 设置jsBundleLoader .setNativeModuleCallExceptionHandler(exceptionHandler); ... final CatalystInstance catalystInstance; try { //创建CatalystInstanceImpl对象 catalystInstance = catalystInstanceBuilder.build(); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END); } // 将CatalystInstanceImpl对象绑定到reactContext上 reactContext.initializeWithInstance(catalystInstance); if (mJSIModulePackage != null) { catalystInstance.addJSIModules( mJSIModulePackage.getJSIModules( reactContext, catalystInstance.getJavaScriptContextHolder())); } ... // 加载jsBundle catalystInstance.runJSBundle(); return reactContext; } 复制代码
首先创建了ReactContext对象,然后创建了CatalystInstanceImpl对象并绑定到ReactContext,然后调用CatalystInstanceImpl对象的runJSBundle方法来加载jsBundle。等会再说什么是加载jsBundle,先来看看CatalystInstanceImpl对象。
2.3.1 CatalystInstanceImpl的初始化
CatalystInstanceImpl可以说承载了ReactContext的核心功能,它的初始化十分重要,我们来看看CatalystInstanceImpl在初始化做了什么。
public class CatalystInstanceImpl implements CatalystInstance { static { // 加载so库中的reactnativejni库 ReactBridge.staticInit(); } private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1); // Access from any thread private final ReactQueueConfigurationImpl mReactQueueConfiguration; private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners; private final AtomicInteger mPendingJSCalls = new AtomicInteger(0); private final String mJsPendingCallsTitleForTrace = "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement(); private volatile boolean mDestroyed = false; private final TraceListener mTraceListener; private final JavaScriptModuleRegistry mJSModuleRegistry; private final JSBundleLoader mJSBundleLoader; private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>(); private final Object mJSCallsPendingInitLock = new Object(); private final NativeModuleRegistry mNativeModuleRegistry; private final JSIModuleRegistry mJSIModuleRegistry = new JSIModuleRegistry(); private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; private final MessageQueueThread mNativeModulesQueueThread; private boolean mInitialized = false; private volatile boolean mAcceptCalls = false; private boolean mJSBundleHasLoaded; private @Nullable String mSourceURL; private JavaScriptContextHolder mJavaScriptContextHolder; private volatile @Nullable TurboModuleRegistry mTurboModuleRegistry = null; private @Nullable JSIModule mTurboModuleManagerJSIModule = null; // C++ parts,native方法 private final HybridData mHybridData; private static native HybridData initHybrid( boolean enableRuntimeScheduler, boolean enableRuntimeSchedulerInTurboModule); public native CallInvokerHolderImpl getJSCallInvokerHolder(); public native CallInvokerHolderImpl getNativeCallInvokerHolder(); // 构造函数 private CatalystInstanceImpl( final ReactQueueConfigurationSpec reactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry nativeModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { ... mReactQueueConfiguration = // 调用ReactQueueConfigurationImpl的静态方法,来创建整个通信体系要用到的线程 ReactQueueConfigurationImpl.create( reactQueueConfigurationSpec, new NativeExceptionHandler()); mBridgeIdleListeners = new CopyOnWriteArrayList<>(); mNativeModuleRegistry = nativeModuleRegistry; // nativeModule注册表 mJSModuleRegistry = new JavaScriptModuleRegistry();// JavaScriptModule注册表 mJSBundleLoader = jsBundleLoader; mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread(); mTraceListener = new JSProfilerTraceListener(this); ... // native方法,初始化c++通信桥 initializeBridge( new BridgeCallback(this), jsExecutor, mReactQueueConfiguration.getJSQueueThread(), mNativeModulesQueueThread, mNativeModuleRegistry.getJavaModules(this),// nativeModules中Js调用java的部分 mNativeModuleRegistry.getCxxModules());// nativeModules中Js调用c++的部分 ... } } 复制代码
CatalystInstanceImpl在主要做了两件事创建通信体系要用到的线程,创建通信体系底层要用到的c++桥。
2.3.1.1 创建js线程和nativeModules线程
ReactQueueConfigurationImpl.java#create
public class ReactQueueConfigurationImpl implements ReactQueueConfiguration { private final MessageQueueThreadImpl mUIQueueThread; private final MessageQueueThreadImpl mNativeModulesQueueThread; private final MessageQueueThreadImpl mJSQueueThread; ... public static ReactQueueConfigurationImpl create( ReactQueueConfigurationSpec spec, QueueThreadExceptionHandler exceptionHandler) { // 创建一个HashMap Map<MessageQueueThreadSpec, MessageQueueThreadImpl> specsToThreads = MapBuilder.newHashMap(); // UI线程:主线程 MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec(); MessageQueueThreadImpl uiThread = MessageQueueThreadImpl.create(uiThreadSpec, exceptionHandler); specsToThreads.put(uiThreadSpec, uiThread); // js线程:负责执行js代码 MessageQueueThreadImpl jsThread = specsToThreads.get(spec.getJSQueueThreadSpec()); if (jsThread == null) { jsThread = MessageQueueThreadImpl.create(spec.getJSQueueThreadSpec(), exceptionHandler); } // nativeModules线程:处理nativeModules相关内容 MessageQueueThreadImpl nativeModulesThread = specsToThreads.get(spec.getNativeModulesQueueThreadSpec()); if (nativeModulesThread == null) { nativeModulesThread = MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler); } return new ReactQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread); } } 复制代码
用一个HashMap存MessageQueueThreadImpl对象,MessageQueueThreadImpl对象保存了线程相关的信息。
MessageQueueThreadImpl.java#create
public static MessageQueueThreadImpl create( MessageQueueThreadSpec spec, QueueThreadExceptionHandler exceptionHandler) { switch (spec.getThreadType()) { case MAIN_UI: // 直接使用mainLooper创建MessageQueueThreadImpl对象 return createForMainThread(spec.getName(), exceptionHandler); case NEW_BACKGROUND: // 手动创建Looper和线程,然后创建MessageQueueThreadImpl对象。 return startNewBackgroundThread(spec.getName(), spec.getStackSize(), exceptionHandler); default: throw new RuntimeException("Unknown thread type: " + spec.getThreadType()); } } 复制代码
MessageQueueThreadImpl.java#createForMainThread
/** @return a MessageQueueThreadImpl corresponding to Android's main UI thread. */ private static MessageQueueThreadImpl createForMainThread( String name, QueueThreadExceptionHandler exceptionHandler) { Looper mainLooper = Looper.getMainLooper(); final MessageQueueThreadImpl mqt = new MessageQueueThreadImpl(name, mainLooper, exceptionHandler); ... return mqt; } 复制代码
MessageQueueThreadImpl.java#startNewBackgroundThread
private static MessageQueueThreadImpl startNewBackgroundThread( final String name, long stackSize, QueueThreadExceptionHandler exceptionHandler) { ... Thread bgThread = new Thread( null, new Runnable() { @Override public void run() { ... Looper.prepare(); ... Looper.loop(); } }, "mqt_" + name, stackSize); bgThread.start(); return new MessageQueueThreadImpl(name, pair.first, exceptionHandler, pair.second); } 复制代码
2.3.1.2 初始化c++桥
NativeModuleRegistry是在createReactContext()方法创建并添加module的。
JavaScriptModuleRegistry是在CatalystInstanceImpl的构建方法创建并添加module的。
在ReactInstanceManager的构造函数中,有这样一段代码添加了核心的JavaScriptModule
synchronized (mPackages) { PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages"); mPackages.add( new CoreModulesPackage( this, new DefaultHardwareBackBtnHandler() { @Override public void invokeDefaultOnBackPressed() { ReactInstanceManager.this.invokeDefaultOnBackPressed(); } }, mUIImplementationProvider, lazyViewManagersEnabled, minTimeLeftInFrameForNonBatchedOperationMs)); if (mUseDeveloperSupport) { mPackages.add(new DebugCorePackage()); } mPackages.addAll(packages); } 复制代码
initializeBridge方法会通过jni调用native方法完成c++侧的CatalystInstance的初始化。
private native void initializeBridge( ReactCallback callback, // 回调方法,CatalystInstanceImpl的静态内部类ReactCallbac JavaScriptExecutor jsExecutor, // 默认为空 MessageQueueThread jsQueue, // JS线程 MessageQueueThread moduleQueue, // nativeModules线程 Collection<JavaModuleWrapper> javaModules, // nativeModules中Js调用java的部分 Collection<ModuleHolder> cxxModules// nativeModules中Js调用c++的部分 ); 复制代码
javaModules和cxxModules会在CatalystInstanceImpl.cpp的initializeBridge方法中被打包成ModuleRegistry传入Instance.cpp中。
ModuleRegistry再通过Instance的initializeBridge方法传到NativeToJsBridge.cpp中的构造函数中然后传到JsToNativeBridge。
NativeToJsBridge:NativeToJsBridge是java调用js的桥梁,用来调用jsModule。
JsToNativeBridge:JsToNativeBridge是js调用java的桥梁,用来调用nativeModule。
2.3.2 加载jsBundle
加载Js代码本质上就是将jsBundle这个资源文件加载到内存中,加载完就意味着我们开始执行js代码,调用index.js里面的AppRegistry.registerComponent方法来完成组件的注册,但此时渲染还未开始。
AppRegistry.js#registerComponent
registerComponent( appKey: string, // 组件名 componentProvider: ComponentProvider, // 一个返回组件的函数 section?: boolean, ): string { let scopedPerformanceLogger = createPerformanceLogger(); // runnables是一个存放键值对的对象,可以理解成map。 runnables[appKey] = { componentProvider, run: (appParameters, displayMode) => { renderApplication( // 渲染入口方法,此时还未被调用。等run方法被调用时才开始渲染。 componentProviderInstrumentationHook( componentProvider, scopedPerformanceLogger, ), appParameters.initialProps, appParameters.rootTag, wrapperComponentProvider && wrapperComponentProvider(appParameters), appParameters.fabric, showArchitectureIndicator, scopedPerformanceLogger, appKey === 'LogBox', appKey, coerceDisplayMode(displayMode), appParameters.concurrentRoot, ); }, }; if (section) { sections[appKey] = runnables[appKey]; } return appKey; }, 复制代码
CatalystInstanceImpl是怎么加载jsBundle的呢?
CatalystInstanceImpl.java#runJSBundle
public void runJSBundle() { ... // 传入CatalystInstanceImpl对象 mJSBundleLoader.loadScript(CatalystInstanceImpl.this); ... } 复制代码
内部直接调用mJSBundleLoader的loadScript,mJSBundleLoade就是在前面的ReactInstanceManagerBuilder.java#build
中调用JSBundleLoader.createAssetLoader创建的。
JSBundleLoader.java#createAssetLoader
public abstract class JSBundleLoader { public static JSBundleLoader createAssetLoader( final Context context, final String assetUrl, final boolean loadSynchronously) { return new JSBundleLoader() { @Override public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously); return assetUrl; } }; } ... } 复制代码
总共有三种加载jsBundle的方式:
setSourceURLs(String deviceURL, String remoteURL) :从远程服务器加载
loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously):从Assets文件夹加载
loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously):从文件路径加载
观察创建ReactInstanceManager的部分就会知道,dev模式下会从远程服务下载,默认是使用第二种加载Assets文件夹下的"index.android.bundle"文件,如果同时配置了第二和第三种,第三种优先级更高。
loadScript方法的参数是JSBundleLoaderDelegate对象,而前面传入了CatalystInstanceImpl对象,不出意外CatalystInstanceImpl就是
JSBundleLoaderDelegate对象。
public class CatalystInstanceImpl implements CatalystInstance {} 复制代码
public interface CatalystInstance extends MemoryPressureListener, JSInstance, JSBundleLoaderDelegate {} 复制代码
是了是了,也就是说加载jsBundle最终调用了CatalystInstanceImpl的loadScriptFromAssets方法。
CatalystInstanceImpl.java#loadScriptFromAssets
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously); @Override public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) { mSourceURL = assetURL; jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously); } 复制代码
最终加载jsBundle是通过jni的方式,调用了native方法jniLoadScriptFromAssets。(这里的native指的是c/c++)
在c++层完成加载jsBundle后,会进入MessageQueue.js开始执行js代码。
2.4 setupReactContext
前面说到创建万ReactContext后还要调用setupReactContext方法
ReactInstanceManager.java#setupReactContext
private void setupReactContext(final ReactApplicationContext reactContext) { ... synchronized (mAttachedReactRoots) { synchronized (mReactContextLock) { mCurrentReactContext = Assertions.assertNotNull(reactContext); } CatalystInstance catalystInstance = Assertions.assertNotNull(reactContext.getCatalystInstance()); catalystInstance.initialize(); ... for (ReactRoot reactRoot : mAttachedReactRoots) { if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) { // 将ReactRoot绑定到ReactInstanceManager attachRootViewToInstance(reactRoot); } } } ... } 复制代码
ReactInstanceManager.java#attachRootViewToInstance
private void attachRootViewToInstance(final ReactRoot reactRoot) { @Nullable UIManager uiManager = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); ... // ReactRootView.startApplication传的mLaunchOptions @Nullable Bundle initialProperties = reactRoot.getAppProperties(); final int rootTag; if (reactRoot.getUIManagerType() == FABRIC) { rootTag = uiManager.startSurface( reactRoot.getRootViewGroup(), reactRoot.getJSModuleName(), initialProperties == null ? new WritableNativeMap() : Arguments.fromBundle(initialProperties), reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec()); reactRoot.setRootViewTag(rootTag); reactRoot.setShouldLogContentAppeared(true); } else { // 将ReactRootView添加到UIManager上,会返回一个int型的rootTag来标识ReactRootView rootTag = uiManager.addRootView( reactRoot.getRootViewGroup(), initialProperties == null ? new WritableNativeMap() : Arguments.fromBundle(initialProperties), reactRoot.getInitialUITemplate()); reactRoot.setRootViewTag(rootTag); // 启动ReactRootView reactRoot.runApplication(); } ... } 复制代码
ReactRootView.java#runApplication
public void runApplication() { try { if (mReactInstanceManager == null || !mIsAttachedToInstance) { return; } ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); if (reactContext == null) { return; } CatalystInstance catalystInstance = reactContext.getCatalystInstance(); // 获取主组件名 String jsAppModuleName = getJSModuleName(); if (mWasMeasured) { updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec); } WritableNativeMap appParams = new WritableNativeMap(); // 打包rootTag和appProperties到appParams appParams.putDouble("rootTag", getRootViewTag()); @Nullable Bundle appProperties = getAppProperties(); if (appProperties != null) { appParams.putMap("initialProps", Arguments.fromBundle(appProperties)); } mShouldLogContentAppeared = true; // 调用AppRegistry这个JavaScriptModule的runApplication方法,传入主组件名和参数 catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } 复制代码
至此就到达了进入js世界的入口,也就是调用了js代码的AppRegistry.runApplication方法。正式开始渲染rn组件。
AppRegistry.js#runApplication
runApplication( appKey: string, appParameters: any, displayMode?: number, ): void { ... runnables[appKey].run(appParameters, displayMode);// 取出之前注册的对象,执行run方法 }, 复制代码
来看前面注册时,run方法内部的renderApplication方法:
renderApplication.js#renderApplication
function renderApplication<Props: Object>( RootComponent: React.ComponentType<Props>, initialProps: Props, rootTag: any, WrapperComponent?: ?React.ComponentType<any>, fabric?: boolean, showArchitectureIndicator?: boolean, scopedPerformanceLogger?: IPerformanceLogger, isLogBox?: boolean, debugName?: string, displayMode?: ?DisplayModeType, useConcurrentRoot?: boolean, ) { ... let renderable = ( <PerformanceLoggerContext.Provider value={performanceLogger}> <AppContainer rootTag={rootTag} fabric={fabric} showArchitectureIndicator={showArchitectureIndicator} WrapperComponent={WrapperComponent} initialProps={initialProps ?? Object.freeze({})} internal_excludeLogBox={isLogBox}> <RootComponent {...initialProps} rootTag={rootTag} /> // 这里的RootComponent就是前面注册的组件,这里将原生传过来的initialProps和rootTag作为属性传给RootComponent </AppContainer> </PerformanceLoggerContext.Provider> ); ... if (fabric) { require('../Renderer/shims/ReactFabric').render( renderable, rootTag, null, useConcurrentRoot, ); } else { require('../Renderer/shims/ReactNative').render(renderable, rootTag); } ... } 复制代码
至此组件开始渲染,先写到这。刚毕业工作,对源码的阅读可能会出错,请多多理解。后续有时间可能会写对RN打包流程,RN拆包原理,RN资源文件加载,以及原生如何多包加载和预渲染相关内容。
作者:zhan_haoyu
链接:https://juejin.cn/post/7056277323494424583