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(
                          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();
  }

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、创建CatalystInstanceImpl

  private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoaderReact Native 源码分析——启动流程

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

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

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

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

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