阅读 82

从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


文章分类
ANDROID
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐