react-native啟動(dòng)流程(android端)

一、前言

???????好吧,其實(shí)就是想看看rn在android上是怎么啟動(dòng)的,因?yàn)槲沂莻€(gè)android攻城師,出于對(duì)新技術(shù)的追求(公司項(xiàng)目需要),我開始了我的rn之旅。我想在搜索這篇文章的你應(yīng)該也是一個(gè)對(duì)android有一定基礎(chǔ)的同學(xué),也該有一定的基礎(chǔ),這樣你才能看下去,若是沒有,我不建議你繼續(xù)閱讀下去(那是浪費(fèi)時(shí)間)。

二、分析前的場(chǎng)景介紹

???????為了更好的(沒有干擾)的分析啟動(dòng)流程,我們新建一個(gè)空白的rn項(xiàng)目,通過react-native init testGradle命令生成一個(gè)名為testGradle的新的rn項(xiàng)目,該命令會(huì)為按照一定的結(jié)構(gòu)生成一些目錄和文件,進(jìn)入我們熟悉的android>app>src.main.java.com.testgradle目錄,我們會(huì)看到已經(jīng)為我們默認(rèn)生成了一個(gè)MainActivity.java和MainApplication.java兩個(gè)文件,通過文件的后綴我們不難猜想到這兩個(gè)java類分別繼承了Activity和Application這兩個(gè)類,在這兒我得說一下,rn生成的在android上的應(yīng)用和原生java寫的android應(yīng)用在本質(zhì)上沒什么區(qū)別,因此我可以用分析android應(yīng)用啟動(dòng)的流程方式來分析rn生成的應(yīng)用在android上的啟動(dòng)流程。

三、分析步驟

1.MainApplication.java

??????熟悉android應(yīng)用啟動(dòng)流程的同學(xué)應(yīng)該知道,android應(yīng)用在啟動(dòng)(調(diào)用生命周期方法onCreate)第一個(gè)Activity之前會(huì)先創(chuàng)建一個(gè)全局唯一的Application對(duì)象,關(guān)于application對(duì)象的創(chuàng)建時(shí)機(jī)分析,沒有在網(wǎng)上找到合適的文章,等我有空再補(bǔ)上吧,這篇文章是關(guān)于Android應(yīng)用程序啟動(dòng)過程源代碼分析也提到了application的創(chuàng)建,不過文章比較長,但的確寫的很好,大神之做,建議細(xì)細(xì)品味!

首先來分析下MainApplication.java這個(gè)文件, 它的繼承結(jié)構(gòu)如下


image.png

在MainApplication對(duì)象創(chuàng)建時(shí),創(chuàng)建成員變量mReactNativeHost對(duì)象,進(jìn)而注入了一些配置,主要注入配置如下:

  • getUseDeveloperSupport() 配置是否開啟調(diào)試
  • getPackages() 配置要加載的模塊
  • getJSMainModuleName() 配置js模塊的入口文件名
2.MainActivity.java 進(jìn)入主要啟動(dòng)流程

??????這個(gè)activity是第一個(gè)啟動(dòng)的activity,我們通過它來分析啟動(dòng)流程

Step 1.ReactActivityDelegate.loadApk()

??????ReactActivityDelegate類的的說明如下

Delegate class for {@link ReactActivity} and {@link ReactFragmentActivity}. You can subclass this
to provide custom implementations for e.g. {@link #getReactNativeHost()}, if your Application
class doesn't implement {@link ReactApplication}.

??????英文不太好,就不獻(xiàn)丑了,請(qǐng)自行理解。
??????ReactActivityDelegate.java的源代碼位置為react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java

 protected void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());
    getPlainActivity().setContentView(mReactRootView);
  }

這一步主要完成了三件事:

  • 創(chuàng)建了一個(gè)mReactRootView對(duì)象,它是一個(gè)ViewGroup的子類
  • mReactRootView.startReactApplication()開啟rn初始化,并獲得或者創(chuàng)建一個(gè)ReactInstanceManager對(duì)象
  • 通過 getPlainActivity().setContentView(mReactRootView);為當(dāng)前它所代理的Activity設(shè)置顯示的view

在進(jìn)行mReactRootView.startReactApplication()之前,我們來分析下該方法的三個(gè)參數(shù):

  • ReactInstanceManager ,非常重要的一個(gè)對(duì)象,用于管理react中的instance;
  • moduleName,我們這是"testGradle",它必須與js模塊中通過AppRegistry.registerComponent()方法注入的名稱一致;
  • initialProperties,Bundle類型對(duì)象,用于傳遞一些初始化屬性值;

ReactInstanceManager對(duì)象在創(chuàng)建時(shí)會(huì)對(duì)一些管理的對(duì)象進(jìn)行默認(rèn)的初始化,所以它的創(chuàng)建過程很重要,我們先來看看它的創(chuàng)造流程

Step 2.ReactNativeHost.getReactInstanceManager()

??????ReactNativeHost.java的源代碼位置為react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java

//獲取單列的ReactInstanceManager對(duì)象
  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      mReactInstanceManager = createReactInstanceManager();
    }
    return mReactInstanceManager;
  }

ReactInstanceManager對(duì)象是全局唯一的

Step 3.ReactNativeHost.createReactInstanceManager()
//用Builder模式創(chuàng)建一個(gè)ReactInstanceManager對(duì)象
 protected ReactInstanceManager createReactInstanceManager() {
    ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
      .setApplication(mApplication)//設(shè)置Application對(duì)象,這兒就是MainApplication對(duì)象
      .setJSMainModulePath(getJSMainModuleName())//設(shè)置js模塊的入口文件名
      .setUseDeveloperSupport(getUseDeveloperSupport())//設(shè)置是否支持調(diào)試
      .setRedBoxHandler(getRedBoxHandler())//設(shè)置
      .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
      .setUIImplementationProvider(getUIImplementationProvider())
      .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);//設(shè)置當(dāng)前最開始的生命周期狀態(tài)

    for (ReactPackage reactPackage : getPackages()) {//收集所有模塊
      builder.addPackage(reactPackage);
    }

    String jsBundleFile = getJSBundleFile();//獲取要加載的JSBundleFile文件的路徑,這個(gè)方法是熱更新的關(guān)鍵方法
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);//從自定義路徑獲取JSBundleFile文件
    } else {
      //加載默認(rèn)路徑(android項(xiàng)目assets目錄)下的文件名為"index.android.bundle"的JSBundleFile文件,若是文件不存在,程序直接拋出error并退出。
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    return builder.build();
  }

上面代碼主要做了兩件事:

  • 創(chuàng)建一個(gè)ReactInstanceManagerBuilder對(duì)象,并通過該對(duì)象進(jìn)行一些參數(shù)設(shè)置
  • 調(diào)用ReactInstanceManagerBuilder對(duì)象的build()方法創(chuàng)造ReactInstanceManager對(duì)象

我們接下里繼續(xù)分析ReactInstanceManagerBuilder的build()方法

step 4.ReactInstanceManagerBuilder.build()

??????ReactRootView.java源代碼位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java

public ReactInstanceManager build() {

    Assertions.assertNotNull(
      mApplication,
      "Application property has not been set with this builder");

    Assertions.assertCondition(
      mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null,
      "JS Bundle File or Asset URL has to be provided when dev support is disabled");

    Assertions.assertCondition(
      mJSMainModulePath != null || mJSBundleAssetUrl != null || mJSBundleLoader != null,
      "Either MainModulePath or JS Bundle File needs to be provided");

    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
    String appName = mApplication.getPackageName();
    String deviceName = getFriendlyDeviceName();

    return new ReactInstanceManager(
        mApplication,//就是MainApplication
        mCurrentActivity,//就是MainaActivity
        mDefaultHardwareBackBtnHandler,//物理返回鍵的處理類,這兒是null
        mJavaScriptExecutorFactory == null//java層js調(diào)用執(zhí)行器,持有一些c++/java的混合對(duì)象
            ? new JSCJavaScriptExecutorFactory(appName, deviceName)
            : mJavaScriptExecutorFactory,
        (mJSBundleLoader == null && mJSBundleAssetUrl != null)//JSBundle文件的信息存儲(chǔ)類,CatalystInstance用它來加載正確的JSBundle文件
            ? JSBundleLoader.createAssetLoader(
                mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
            : mJSBundleLoader,
        mJSMainModulePath,//這兒為默認(rèn)值"index.android";
        mPackages,//一個(gè)Arraylist集合,收集了所有的模塊的package
        mUseDeveloperSupport,//是否支持調(diào)試
        mBridgeIdleDebugListener,//監(jiān)聽bridge的狀態(tài)(空閑和忙碌)
        Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),//檢查生命周期狀態(tài)是否設(shè)置,若沒有設(shè)置,則給出提示,并中斷程序
        mUIImplementationProvider,//
        mNativeModuleCallExceptionHandler,//js調(diào)用本地模塊時(shí)的異常,可以自行定義異常處理方式
        mRedBoxHandler,//一個(gè)監(jiān)聽接口,通過它可以在DevSupportManagerImpl中攔截到開發(fā)狀態(tài)下的異常信息
        mLazyNativeModulesEnabled,//
        mLazyViewManagersEnabled,
        mDelayViewManagerClassLoadsEnabled,
        mDevBundleDownloadListener,
        mMinNumShakes,
        mMinTimeLeftInFrameForNonBatchedOperationMs);
  }

上面代碼進(jìn)行主要做了兩件事:

  • 創(chuàng)建ReactInstanceManager對(duì)象前,檢查必要的設(shè)置是否已經(jīng)調(diào)用
  • 創(chuàng)建ReactInstanceManager對(duì)象,并注入一些對(duì)象

接下來調(diào)用了ReactInstanceManager的構(gòu)造函數(shù)進(jìn)行創(chuàng)建對(duì)象,構(gòu)造函數(shù)中又有一些重要對(duì)象的初始化,我們來看看

step 5.ReactInstanceManager構(gòu)造函數(shù)

??????ReactRootView.java源代碼位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

/* package */ ReactInstanceManager(
      Context applicationContext,
      @Nullable Activity currentActivity,
      @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler,
      JavaScriptExecutorFactory javaScriptExecutorFactory,
      @Nullable JSBundleLoader bundleLoader,
      @Nullable String jsMainModulePath,
      List<ReactPackage> packages,
      boolean useDeveloperSupport,
      @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
      LifecycleState initialLifecycleState,
      UIImplementationProvider uiImplementationProvider,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
      @Nullable RedBoxHandler redBoxHandler,
      boolean lazyNativeModulesEnabled,
      boolean lazyViewManagersEnabled,
      boolean delayViewManagerClassLoadsEnabled,
      @Nullable DevBundleDownloadListener devBundleDownloadListener,
      int minNumShakes,
      int minTimeLeftInFrameForNonBatchedOperationMs) {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()");
    initializeSoLoaderIfNecessary(applicationContext);

    DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);

    mApplicationContext = applicationContext;
    mCurrentActivity = currentActivity;
    mDefaultBackButtonImpl = defaultHardwareBackBtnHandler;
    mJavaScriptExecutorFactory = javaScriptExecutorFactory;
    mBundleLoader = bundleLoader;
    mJSMainModulePath = jsMainModulePath;
    mPackages = new ArrayList<>();
    mInitFunctions = new ArrayList<>();
    mUseDeveloperSupport = useDeveloperSupport;
    mDevSupportManager =
        DevSupportManagerFactory.create(
            applicationContext,
            createDevHelperInterface(),
            mJSMainModulePath,
            useDeveloperSupport,
            redBoxHandler,
            devBundleDownloadListener,
            minNumShakes);
    mBridgeIdleDebugListener = bridgeIdleDebugListener;
    mLifecycleState = initialLifecycleState;
    mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mLazyNativeModulesEnabled = lazyNativeModulesEnabled;
    mDelayViewManagerClassLoadsEnabled = delayViewManagerClassLoadsEnabled;
    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();
                }
              },
              uiImplementationProvider,
              lazyViewManagersEnabled,
              minTimeLeftInFrameForNonBatchedOperationMs));
      if (mUseDeveloperSupport) {
        mPackages.add(new DebugCorePackage());
      }
      mPackages.addAll(packages);
    }

    // Instantiate ReactChoreographer in UI thread.
    ReactChoreographer.initialize();
    if (mUseDeveloperSupport) {
      mDevSupportManager.startInspector();//處于開發(fā)模式,則開啟
    }
  }

上面代碼主要做了四件事:

  • 將構(gòu)造函數(shù)傳入的數(shù)據(jù)賦值給相應(yīng)的變量
  • 創(chuàng)建一個(gè)mDevSupportManager對(duì)象,用于開發(fā)模式的交互
  • 創(chuàng)建一個(gè)CoreModulesPackage類型對(duì)象,封裝了對(duì)物理返回鍵的默認(rèn)處理功能,如果處于開發(fā)模式,則加入DebugCorePackage功能模塊

接下來我們繼續(xù)回到step1中的mReactRootView.startReactApplication()方法

step 5.ReactRootView.startReactApplication()

??????ReactRootView.java源代碼位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

 public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties) {
      ......
      UiThreadUtil.assertOnUiThread();//判斷是否是在ui線程,不是就拋異常,中斷程序
      Assertions.assertCondition(
        mReactInstanceManager == null,
        "This root view has already been attached to a catalyst instance manager");

      mReactInstanceManager = reactInstanceManager;//持有reactInstanceManager
      mJSModuleName = moduleName;
      mAppProperties = initialProperties;
      
      if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
        mReactInstanceManager.createReactContextInBackground();//初始化ReactContext
      }

      attachToReactInstanceManager();//將自己關(guān)聯(lián)到ReactInstanceManager對(duì)象上
      ......
  }

上面這步主要完成了三件事:

  • 將傳入的三個(gè)參數(shù)reactInstanceManager、moduleName、initialProperties賦值給了ReactRootView對(duì)象
  • 開始初始化話ReactContext
  • 將自己關(guān)聯(lián)到ReactInstanceManager對(duì)象上,

當(dāng)前場(chǎng)景下mReactInstanceManager.hasStartedCreatingInitialContext()為false,我們進(jìn)入 mReactInstanceManager.createReactContextInBackground()。

step 6.ReactInstanceManager.createReactContextInBackground()

??????ReactRootView.java源代碼位于react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

public void createReactContextInBackground() {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()");
    //mHasStartedCreatingInitialContext用于標(biāo)識(shí)createReactContextInBackground()方法是否調(diào)用過
    Assertions.assertCondition(
        !mHasStartedCreatingInitialContext,
        "createReactContextInBackground should only be called when creating the react " +
            "application for the first time. When reloading JS, e.g. from a new file, explicitly" +
            "use recreateReactContextInBackground");

    mHasStartedCreatingInitialContext = true;
    recreateReactContextInBackgroundInner();
  }

上面這步做了兩件事

  • 判斷createReactContextInBackground()是否已經(jīng)調(diào)用過了,是則拋出異常,中斷程序
  • 將createReactContextInBackground()方法是已經(jīng)被調(diào)用的flag設(shè)置為true,并調(diào)用recreateReactContextInBackgroundInner()進(jìn)行ReactContext創(chuàng)造流程
step 7.ReactInstanceManager.recreateReactContextInBackgroundInner()
  private void recreateReactContextInBackgroundInner() {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
    UiThreadUtil.assertOnUiThread();//保證在主線程運(yùn)行
   
    if (mUseDeveloperSupport
        && mJSMainModulePath != null
        && !Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();

      // If remote JS debugging is enabled, load from dev server.
      if (mDevSupportManager.hasUpToDateJSBundleInCache() &&
          !devSettings.isRemoteJSDebugEnabled()) {
        // If there is a up-to-date bundle downloaded from server,
        // with remote JS debugging disabled, always use that.
        onJSBundleLoadedFromServer();
      } else if (mBundleLoader == null) {
        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 dev server is down, disable the remote JS debugging.
                          devSettings.setRemoteJSDebugEnabled(false);
                          recreateReactContextInBackgroundFromBundleLoader();
                        }
                      }
                    });
              }
            });
      }
      return;
    }
    recreateReactContextInBackgroundFromBundleLoader();
  }

由于mUseDeveloperSupport為true,mJSMainModulePath 為"index.android",Systrace.isTracing()為false

未完待續(xù)......
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容