React Native 源码分析——启动流程

Posted 薛瑄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Native 源码分析——启动流程相关的知识,希望对你有一定的参考价值。

本系列文章,是分析android 的 React Native 的源码,主要包括以下文章,和以往的源码系列一样,分析主流程的代码,不会细致到每一行(但相比上一篇的Gradle源码分析,要细致很多),会涉及到java、C++、js等源码。 RN版本是0.64.0

1、React Native 源码分析(一)—— 启动流程
2、React Native 源码分析(二)—— 通信机制
3、React Native 源码分析(三)—— UI渲染流程
4、React Native 源码分析(四)—— 任务调度
5、React Native 源码分析(五)—— 事件分发

在使用RN的时候,Activity需要继承ReactActivity, ReactActivity 的操作都是交给ReactActivityDelegate 来处理的,所以下面我们从ReactActivityDelegate的onCreate来开始

一、RN框架初始化

1.1、ReactActivityDelegate # onCreate

  protected void onCreate(Bundle savedInstanceState) 
    //该函数在自己activity 重写
    //后续进入React,会通过该名称,在js中寻找注册的同名组件,进行启动。
    //js中 这样注册 AppRegistry.registerComponent(appName, () => Root);
    String mainComponentName = getMainComponentName();
    //创建ReactDelegate,
    //参数getPlainActivity() 是当前的activity
    //参数getReactNativeHost() 返回一个ReactNativeHost对象,是在Application中实现
    mReactDelegate =
        new ReactDelegate(
            getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) 

         //复写函数 创建RootView,后续RN的界面,都在这个View中承载
          @Override
          protected ReactRootView createRootView() 
            return ReactActivityDelegate.this.createRootView();
          
        ;
    if (mMainComponentName != null) 
     // 加载javaModule、jsModule、创建UI线程、Native线程、js线程等等
      loadApp(mainComponentName);
    
  

  protected void loadApp(String appKey) 
    //代码1.2 分析
    mReactDelegate.loadApp(appKey);
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  

1.2、ReactDelegate#loadApp

接着代码1.1 的 mReactDelegate.loadApp(appKey);继续分析

  public void loadApp(String appKey) 
    ...
    //会调用到代码1.1
    mReactRootView = createRootView();
    //该函数经过几次调用会到代码4
    mReactRootView.startReactApplication(
        //ReactNativeHost 实例是application中创建的,调用getReactInstanceManager,会先去创建ReactInstanceManager
        //具体创建ReactInstanceManager的时机,由业务代码确定,也可能还没执行loadApp,ReactInstanceManager已经创建了
        getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
  

getReactInstanceManager() 获取实例时,如果为空,会先去创建,下面就看看是如何创建的

1.3、 ReactNativeHost # createReactInstanceManager

ReactNativeHost 是一个抽象类,可覆盖 protected、abstract函数,来实现自定义,下面代码中getxxxx()函数都是可以在创建 ReactNativeHost对象时,进行重写

  protected ReactInstanceManager createReactInstanceManager() 
  
    ReactInstanceManagerBuilder builder =
        ReactInstanceManager.builder()
            .setApplication(mApplication)
            .setJSMainModulePath(getJSMainModuleName()) //dev有效,JS主module名称,默认index.android,会从metro拉取js bundle
            .setUseDeveloperSupport(getUseDeveloperSupport()) //是否debug,在ReactNativeHost 的抽象函数去获取
            .setRedBoxHandler(getRedBoxHandler()) //红盒处理器,就是在调试时,出现错误异常,弹窗的红色报错页面
            //自定义生产JS处理器的工厂类,例如:HermesExecutorFactory 、默认JSCExecutorFactory、
            .setjavascriptExecutorFactory(getJavaScriptExecutorFactory()) 
             //RN对UI处理,是通过java的UIManagerModule,该module可让js来操作native view,具体的实现在UIImplementation。       
             //UIImplementation 如何被提供,可通过次 自定义,默认UIImplementationProvider
            .setUIImplementationProvider(getUIImplementationProvider())
            .setJSIModulesPackage(getJSIModulePackage()) //可自定义添加JS module
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);

    //获取自定义添加的java module
    for (ReactPackage reactPackage : getPackages()) 
      builder.addPackage(reactPackage);
    
   //获取js bundle文件
    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) 
      builder.setJSBundleFile(jsBundleFile);
     else 
      //如果没有指定js bundle的路径,那么就指定使用asset中的js bundle文件。默认index.android.bundle
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    
    //创建ReactInstanceManager,把设置的值,赋值到成员变量,增加CoreModulesPackage到java module中 等
    ReactInstanceManager reactInstanceManager = builder.build();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return reactInstanceManager;
  

下面接着代码2的startReactApplication 往下分析,经过几次调用到mReactInstanceManager.createReactContextInBackground()

1.4、ReactInstanceManager#recreateReactContextInBackgroundInner

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundInner() 
    ...
    // 这两个变量在代码3中设置,分别表示:是否是开发者模式、是否有JSMainModuleName
    if (mUseDeveloperSupport && mJSMainModulePath != null) 
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();

      if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) 
        //如果js bundle 路径是assets,则mBundleLoader =  JSBundleLoader.createAssetLoader
        //否则  mBundleLoader = JSBundleLoader.createFileLoader
        //都是异步加载
        if (mBundleLoader == null) 
          mDevSupportManager.handleReloadJS();
         else 
          //通过访问 http://localhost:8081/status 判断packager(e.g. metro)是否在运行,也只有开发的是会,才会出现这样的环境
          mDevSupportManager.isPackagerRunning(
              new PackagerStatusCallback() 
                @Override
                public void onPackagerStatusFetched(final boolean packagerIsRunning) 
                  //在UI线程中运行,把下面的任务加入loop的队列
                  //在实际的调试中,发现执行下面的代码之前,会执行代码1 的setContentView。

                  UiThreadUtil.runOnUiThread(
                      new Runnable() 
                        @Override
                        public void run() 
                          if (packagerIsRunning) 
                            mDevSupportManager.handleReloadJS();
                           else if (mDevSupportManager.hasUpToDateJSBundleInCache()
                              && !devSettings.isRemoteJSDebugEnabled()) 

                             //hasUpToDateJSBundleInCache 是比较 Context.getFilesDir()下的文件修改事件和当前app的最后更新时间
                            // 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();
  

onJSBundleLoadedFromServerrecreateReactContextInBackgroundFromBundleLoader 最终都会调用到recreateReactContextInBackground,只是参数JSBundleLoader 有差异 (前者是JSBundleLoader.createCachedBundleFromNetworkLoader, 后者是 mBundleLoader),这两个参数最终会传到ReactContextInitParams 中,如下:

  @ThreadConfined(UI)
  private void recreateReactContextInBackground(
    ...
    UiThreadUtil.assertOnUiThread();

    final ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    //这是一个volatile 变量,因为调用该函数前,会判断它是否为空,为空才会继续执行到这里。
    if (mCreateReactContextThread == null) 
      //在下面的代码分析
      runCreateReactContextOnNewThread(initParams);
     else 
      //如果mCreateReactContextThread 在创建的过程,此时又需要创建,就把参数放置在该变量中,
      //在当前正在运行的mCreateReactContextThread中,进行判断,如果不为空,就重新创建
      mPendingReactContextInitParams = initParams;
    
  

在实际调试中发现,runCreateReactContextOnNewThread 是在线程mCreateReactContextThread中执行,此处可能会先执行代码1 的setContentView。

@ThreadConfined(UI)
  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) 
    ...
    //在activity destroy() 和 它自身线程执行  会置空
    mCreateReactContextThread =
        new Thread(
            null,
            new Runnable() 
              @Override
              public void run() 
                ReactMarker.logMarker(REACT_CONTEXT_THREAD_END);
                synchronized (ReactInstanceManager.this.mHasStartedDestroying) 
                  while (ReactInstanceManager.this.mHasStartedDestroying) 
                    try 
                      ReactInstanceManager.this.mHasStartedDestroying.wait();
                     catch (InterruptedException e) 
                      continue;
                    
                  
                
                // As destroy() may have run and set this to false, ensure that it is true before we
                // create
                mHasStartedCreatingInitialContext = true;

                try 
                  Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
                  
                  //创建ReactContext,代码1.5 分析
                  final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                           //这里create 并不是正常 创建JsExecutor,只是创建了C++层JavaScriptExecutorHolder父类的对应java类对象
                           //把该对象传递到c++,代码2.3的 *jseh
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());

                  mCreateReactContextThread = null;
                 
                  final Runnable maybeRecreateReactContextRunnable =
                      new Runnable() 
                        @Override
                        public void run() 
                          //该值是在上方代码段中设置的
                          if (mPendingReactContextInitParams != null) 
                            runCreateReactContextOnNewThread(mPendingReactContextInitParams);
                            mPendingReactContextInitParams = null;
                          
                        
                      ;
                  Runnable setupReactContextRunnable =
                      new Runnable() 
                        @Override
                        public void run() 
                          try 
                            //代码1.8 分析
                            setupReactContext(reactApplicationContext);
                           ...
                        
                      ;

                  reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
                  UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
                 catch (Exception e) 
                  mDevSupportManager.handleException(e);
                
              
            ,
            "create_react_context");
    ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
    mCreateReactContextThread.start();
  

假如initParams.getJsExecutorFactory().create() 创建的为 HermesExecutor,来看下它对应c++的类HermesExecutorHolder,路径

ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp ,它的父类JavaScriptExecutorHolder,路径ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h。调用函数getExecutorFactory,获取工厂类,继而创建JsExecutor

1.5、ReactInstanceManager# createReactContext

 private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) 

    ...
    final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

    //异常处理器,也是在ReactInstanceManagerBuilder中可配置
    NativeModuleCallExceptionHandler exceptionHandler =
        mNativeModuleCallExceptionHandler != null
            ? mNativeModuleCallExceptionHandler
            : mDevSupportManager;
    reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
    //代码1.6 分析该函数
    //函数就是把各个ReactPackage的所有NativeModule提取出来,
    //以 Map<String, ModuleHolder> 的形式保存,再封装成NativeModuleRegistry。
    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);

    CatalystInstanceImpl.Builder catalystInstanceBuilder =
        new CatalystInstanceImpl.Builder()
             //设置创建线程的配置项,第二章节会分析线程的创建流程
            .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
            //js 执行器,代码三中设置
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            //代码四分析,三种JSBundleLoader
            .setJSBundleLoader(jsBundleLoader)
            .setNativeModuleCallExceptionHandler(exceptionHandler);

    ...
    final CatalystInstance catalystInstance;
    try 
      //代码1.7分析
      catalystInstance = catalystInstanceBuilder.build();
     ...
    
    //设置catalystInstance、三大线程到 ReactContext 的成员变量中
    reactContext.initializeWithInstance(catalystInstance);
    //这个参数是在ReactNativeHost setxxx 对应的函数设置的
    if (mJSIModulePackage != null) 
      catalystInstance.addJSIModules(
          mJSIModulePackage.getJSIModules(
              reactContext, catalystInstance.getJavaScriptContextHolder()));
              
      //turbo、jsi都是RN 新架构中用到的,不需要桥通信(也就是说可以实现同步调用),
      //相关的module也需要改变,对应的就是turbo,有TurboCxxModule、JavaTurboModule。
      //本系列文章的最后一篇再来讨论这些新特性
      if (ReactFeatureFlags.useTurboModules) 
        JSIModule turboModuleManager =
            catalystInstance.getJSIModule(JSIModuleType.TurboModuleManager);
        catalystInstance.setTurboModuleManager(turboModuleManager);
        TurboModuleRegistry registry = (TurboModuleRegistry) turboModuleManager;

        // Eagerly initialize TurboModules
        for (String moduleName : registry.getEagerInitModuleNames()) 
          registry.getModule(moduleName);
        
      
    
    if (ReactFeatureFlags.eagerInitializeFabric) 
      catalystInstance.getJSIModule(JSIModuleType.UIManager);
    
    //添加 通信桥空闲时 的回调函数,这个在计算js帧率的时候,会用到
    if (mBridgeIdleDebugListener != null) 
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    
    ...
    //在通信机制的文章 详细分析
    catalystInstance.runJSBundle();

    return reactContext;
  

1.6、processPackages

该函数就是把各个ReactPackage的所有NativeModule提取出来,以 Map<String, ModuleHolder> 的形式保存,再封装成NativeModuleRegistry。 其中ModuleHolder 包括NativeModule继承类的基本信息,class名称、module名称等

  private NativeModuleRegistry processPackages(
      ReactApplicationContext reactContext,
      List<ReactPackage> packages,
      boolean checkAndUpdatePackageMembership) 

    //最后是通过该变量来创建NativeModuleRegistry
    NativeModuleRegistryBuilder nativeModuleRegistryBuilder =
        new NativeModuleRegistryBuilder(reactContext, this);

    ...
    synchronized (mPackages) 
      for (ReactPackage reactPackage : packages) 
        //该变量为true 
        if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage)) 
          //true 则终止本次循环
          continue;
        
       
        try 
          //true 则 把当前循环的 reactPackage 加入到mPackages。结合上方判断,意思是,只更新 新添加的reactPackage
          if (checkAndUpdatePackageMembership) 
            mPackages.add(reactPackage);
          
          //解析每个ReactPackage中的nativeModule
          processPackage(reactPackage, nativeModuleRegistryBuilder);
        ... 
      
    
   ...
    NativeModuleRegistry nativeModuleRegistry;
    try 
      //build,是把收集好的 Map<String, ModuleHolder> 作为参数,创建NativeModuleRegistry
      nativeModuleRegistry = nativeModuleRegistryBuilder.build();
     ...

    return nativeModuleRegistry;
  

  private void processPackage(
      ReactPackage reactPackage, NativeModuleRegistryBuilder nativeModuleRegistryBuilder) 
    ...
    nativeModuleRegistryBuilder.processPackage(reactPackage);
     ...
  
  public void processPackage(ReactPackage reactPackage) 
    // We use an iterable instead of an iterator here to ensure thread safety, and that this list
    // cannot be modified
    Iterable<ModuleHolder> moduleHolders;
    //根据不同的ReactPackage 类型来处理,原理都是先用reactPackage 的NativeModule 创建Iterable,然后就可以依次取出
    if (reactPackage instanceof LazyReactPackage) 
      moduleHolders =
          ((LazyReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
     else if (reactPackage instanceof TurboReactPackage) 
      moduleHolders =
          ((TurboReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
     else 
      moduleHolders =
          ReactPackageHelper.getNativeModuleIterator(
              reactPackage, mReactApplicationContext, mReactInstanceManager);
    
    
    for (ModuleHolder moduleHolder : moduleHolders) 
      String name = moduleHolder.getName();
      if (mModules.containsKey(name)) 
        ModuleHolder existingNativeModule = mModules.get(name);
        ...
        mModules.remove(existingNativeModule);
      
      mModules.put(name, moduleHolder);
    
  

代码1.5中 catalystInstanceBuilder.build(); 会创建CatalystInstanceImpl,builder模式,就不进去看了,直接看CatalystInstanceImpl的构造函数

1.7、创

以上是关于React Native 源码分析——启动流程的主要内容,如果未能解决你的问题,请参考以下文章

React Native 源码分析——启动流程

React Native 源码分析——启动流程

React Native 源码分析——启动流程

React Native 源码分析——Native View创建流程

React Native 源码分析——Native View创建流程

React Native 源码分析——Native View创建流程