1. 程式人生 > >react-native 啟動流程原理解析

react-native 啟動流程原理解析

前言

專案中用到RN也有一段時間了, 從剛開始的懵懂到現在的熟能生巧,其實還是很長的,每次接觸一個新的東西的時候,剛開始一定是比較痛苦的,不知道要如何下手,這裡從js到Android原生去一步步解析React Native是如何做到如此巧妙的通訊的。希望能對你們有所幫助。

這裡以我目前專案中用到的版本為例:

{
    "react": "16.0.0-alpha.12",
    "react-native": "^0.46.4",
}

JS

我們先從js端入手

 import { AppRegistry } from 'react-native'
 ...省略程式碼

 AppRegistry.registerComponent('xemall'
, () => Index)

上述程式碼就是JS程式的入口,將當前APP物件註冊到AppRegistry元件中,AppRegistry元件是js module。

啟動流程

我們新建一個RN的專案,在原生程式碼中會生成MainActivityMainApplication兩個Java類。顧名思義,MainAcitivity就是我們的Native的入口了,

我們先來看下MainApplication都做了哪些操作:

public class MainApplication extends Application implements ReactApplication {
    //ReactNativeHost:持有ReactInstanceManager例項,做一些初始化操作。
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new
MainReactPackage() ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); //SoLoader:載入C++底層庫,準備解析JS。 SoLoader.init(this, /* native exopackage */ false); } } }

我們再來看下MainActivity的程式碼:

public class MainActivity extends ReactActivity {

    @Override
    protected String getMainComponentName() {
        return "xemall";
    }
}

可以看到其實是繼承了ReactActivity類,只是重寫了getMainComponentName方法,有沒有看出來,其方法的返回值和我們在JS端的值是一樣的。如果不一致會怎麼樣,你可以自己試一下。

ReactActivity

我們來看下ReactActivity的方法的onCreate方法:

public abstract class ReactActivity extends Activity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
    private final ReactActivityDelegate mDelegate;

    ...省略程式碼

     @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }    
}

ReactActivity全權委託給ReactActivityDelegate來處理。

ReactActivityDelegate

public class ReactActivityDelegate {
      protected void onCreate(Bundle savedInstanceState) {
      // 彈框許可權判斷
    boolean needsOverlayPermission = false;
    if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(getContext())) {
        needsOverlayPermission = true;
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName()));
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
        ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE);
      }
    }
        // 載入組建邏輯 mMainComponentName為getMainComponentName返回的值
    if (mMainComponentName != null && !needsOverlayPermission) {
      loadApp(mMainComponentName);
    }
    // 雙擊判斷工具類
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

  protected void loadApp(String appKey) {
     //空判斷
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    // 建立 RN容器根檢視
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());
      //將rootview新增入activity
    getPlainActivity().setContentView(mReactRootView);
  }
}

loadApp做了三件事:建立RootView、建立ReactApplication、建立ReactInstanceManager

ReactRootView

ReactRootView是一個自定義的View,其父類是FrameLayout。因此,可以把RN看成是一個特殊的 “自定義View”。

我們來看下startReactApplication方法:

 public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties) {
        ...省略程式碼
    try {
        //在UI執行緒中進行
      UiThreadUtil.assertOnUiThread();

      Assertions.assertCondition(
        mReactInstanceManager == null,
        "This root view has already been attached to a catalyst instance manager");
        // 賦值
      mReactInstanceManager = reactInstanceManager;
      mJSModuleName = moduleName;
      mAppProperties = initialProperties;
        // 判斷ReactContext是否初始化,沒有就非同步進行初始化
      if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
        mReactInstanceManager.createReactContextInBackground();
      }
        //寬高計算完成後添加布局監聽
      attachToReactInstanceManager();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

startReactApplication中的三個引數:

形參 描述
reactInstanceManager ReactInstanceManager型別,建立和管理CatalyInstance的例項
moduleName 就是之前的元件名
initialProperties 是Native向JS傳遞的資料,以後可能由POJO代替,預設是null,需要的話要重寫createReactActivityDelegate ,並重寫其中getLaunchOptions方法

startReactApplication 中呼叫了ReactInstanceManagercreateReactContextInBackground方法。

ReactInstanceManager

  public void createReactContextInBackground() {
    //首次執行
     mHasStartedCreatingInitialContext = true;
    recreateReactContextInBackgroundInner();
  }

該方法只會在application中執行一次,JS過載時,會走recreateReactContextInBackground, 這兩個方法最終都會呼叫recreateReactContextInBackgroundInner方法。

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundInner() {
    // 確保在UI執行緒中執行
    UiThreadUtil.assertOnUiThread();

    if (mUseDeveloperSupport && mJSMainModuleName != null &&
      !Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JSC_CALLS)) {
        // 除錯模式,載入伺服器bundle
      return;
    }
    // 載入本地bundle
    recreateReactContextInBackgroundFromBundleLoader();
  }

  @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    recreateReactContextInBackground(
        new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),
        mBundleLoader);
  }
形參 描述
jsExecutorFactory C++和JS雙向通訊的中轉站
jsBundleLoader bundle載入器,根據ReactNativeHost中的配置決定從哪裡載入bundle檔案
 private void recreateReactContextInBackground(
    JavaScriptExecutor.Factory jsExecutorFactory,
    JSBundleLoader jsBundleLoader) {
    UiThreadUtil.assertOnUiThread();

     //建立ReactContextInitParams物件
    final ReactContextInitParams initParams = new ReactContextInitParams(
      jsExecutorFactory,
      jsBundleLoader);
    if (mCreateReactContextThread == null) {
        // 新增執行緒初始化ReactContext
      runCreateReactContextOnNewThread(initParams);
    } else {
      mPendingReactContextInitParams = initParams;
    }
  }

runCreateReactContextOnNewThread中有一個核心方法createReactContext來建立ReactContext。

 private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor,
      JSBundleLoader jsBundleLoader) {
    // 包裝ApplicationContext
    final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
    //建立JavaModule登錄檔Builder,用來建立JavaModule登錄檔,JavaModule登錄檔將所有的JavaModule註冊到CatalystInstance中。
    NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
      reactContext,
      this,
      mLazyNativeModulesEnabled);
      // 建立JavaScriptModule登錄檔Builder
    JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();
    if (mUseDeveloperSupport) {
      // 除錯模式下,將錯誤交給DevSupportManager處理
      reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
    }

    ...省略程式碼

    try {
      //建立CoreModulesPackage,其中封裝了RN Framework核心功能,通訊、除錯等。
      CoreModulesPackage coreModulesPackage =
        new CoreModulesPackage(
          this,
          mBackBtnHandler,
          mUIImplementationProvider,
          mLazyViewManagersEnabled);
          //把各自的Module新增到對應的登錄檔中
      processPackage(coreModulesPackage, nativeModuleRegistryBuilder, jsModulesBuilder);
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
    // 將我們Application中的ReactPackage迴圈處理,加入對應的登錄檔中。
   for (ReactPackage reactPackage : mPackages) {
        ...省略程式碼
      try {
        processPackage(reactPackage, nativeModuleRegistryBuilder, jsModulesBuilder);
      } finally {
        Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      }
    }
    ...省略程式碼
    //生成Java登錄檔,將Java可呼叫的API暴露給JS
    NativeModuleRegistry nativeModuleRegistry;
    try {
       nativeModuleRegistry = nativeModuleRegistryBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
    }

    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
        ? mNativeModuleCallExceptionHandler
        : mDevSupportManager;
     //構建CatalystInstanceImpl例項
    CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
      .setReactQueueConfigurationSpec(mUseSeparateUIBackgroundThread ?
        ReactQueueConfigurationSpec.createWithSeparateUIBackgroundThread() :
        ReactQueueConfigurationSpec.createDefault())
        //JS執行通訊類
      .setJSExecutor(jsExecutor)
      //Java模組登錄檔
      .setRegistry(nativeModuleRegistry)
      // JS登錄檔
      .setJSModuleRegistry(jsModulesBuilder.build())
      // Bundle載入工具類
      .setJSBundleLoader(jsBundleLoader)
      // 異常處理器
      .setNativeModuleCallExceptionHandler(exceptionHandler);

    // 省略程式碼

   final CatalystInstance catalystInstance;
    try {
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
        //省略程式碼
   }

    if (mBridgeIdleDebugListener != null) {
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    }
    if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JSC_CALLS)) {
 //呼叫CatalystInstanceImpl的Native方法把Java Registry轉換為Json,再由C++層傳送到JS層。     catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
    }

    //關聯ReacContext與CatalystInstance
    reactContext.initializeWithInstance(catalystInstance);
    //通過CatalystInstance開始載入JS Bundle
    catalystInstance.runJSBundle();

    return reactContext;
  }

這段程式碼比較長,看的話會花一定時間,它主要做了這幾件事:

  1. 建立JavaModule登錄檔和JavaScriptModule登錄檔,交給CatalystInstance管理。
  2. 處理ReactPackage,將各自的Module放入對應的登錄檔中。
  3. 通過上面的各個引數建立CatalystInstance例項。
  4. CatalystInstance關聯ReactContext,開始載入JS Bundle

CatalystInstance

我們來看下CatalystInstance的實現類CatalystInstanceImpl的構造方法:

  private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry registry,
      final JavaScriptModuleRegistry jsModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    //用來建立JNI相關方法,並返回mHybridData
    mHybridData = initHybrid();
    // Android UI執行緒、JS執行緒、NativeMOdulesQueue執行緒
    mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
        reactQueueConfigurationSpec,
        new NativeExceptionHandler());
    // 省略程式碼
    //呼叫 C++ 層程式碼進行初始化Bridge
    initializeBridge(
      new BridgeCallback(this),
      jsExecutor,
      mReactQueueConfiguration.getJSQueueThread(),
      mNativeModulesQueueThread,
      mUIBackgroundQueueThread,
      mJavaRegistry.getJavaModules(this),
      mJavaRegistry.getCxxModules());

  }
  private native void initializeBridge(
      ReactCallback callback,
      JavaScriptExecutor jsExecutor,
      MessageQueueThread jsQueue,
      MessageQueueThread moduleQueue,
      MessageQueueThread uiBackgroundQueue,
      Collection<JavaModuleWrapper> javaModules,
      Collection<ModuleHolder> cxxModules);
形參 描述
ReactCallback CatalystInstanceImpl的靜態內部類ReactCallback,負責介面回撥
JavaScriptExecutor JS執行器,將JS的呼叫傳給C++層
MessageQueueThread JS執行緒
MessageQueueThread moduleQueue Java執行緒
MessageQueueThread uiBackgroundQueue UI背景執行緒
javaModules java module
cxxModules c++ module

createReactContext方法中用catalystInstance.runJSBundle() 來載入 JS bundle

  @Override
  public void runJSBundle() {

    ...
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
    ...
  }

JSBundleLoader

CatalystInstanceImpl.runJSBundle()會呼叫JSBundleLoader去載入JS Bundle,由於不同的情況可能會有不同的JSBundleLoader,我們假設其中一種:

public abstract class JSBundleLoader {

  /**
   * This loader is recommended one for release version of your app. In that case local JS executor
   * should be used. JS bundle will be read from assets in native code to save on passing large
   * strings from java to native memory.
   */
  public static JSBundleLoader createAssetLoader(
      final Context context,
      final String assetUrl,
      final boolean loadSynchronously) {
    return new JSBundleLoader() {
      @Override
      public String loadScript(CatalystInstanceImpl instance) {
        instance.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
        return assetUrl;
      }
    };
  }

可以看到它會繼續呼叫CatalystInstance中的loadScriptFromAssets方法

public class CatalystInstanceImpl {

  /* package */ void loadScriptFromAssets(AssetManager assetManager, String assetURL) {
    mSourceURL = assetURL;
    jniLoadScriptFromAssets(assetManager, assetURL);
  }

  private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL);

}

最終呢,還是會呼叫CatalystInstanceImpl.cpp去載入JS Bundle,我們去C++層看一下實現

我們先看下原始碼的結構圖

CatalystInstanceImpl.cpp

在ReactAndroid的Jni中,我們看下相關程式碼:

void CatalystInstanceImpl::jniLoadScriptFromAssets(
    jni::alias_ref<JAssetManager::javaobject> assetManager,
    const std::string& assetURL,
    bool loadSynchronously) {
  const int kAssetsLength = 9;  // strlen("assets://");
  // 獲取soure js Bundle的路徑名
  auto sourceURL = assetURL.substr(kAssetsLength);
  // 獲取AssetManager
  auto manager = extractAssetManager(assetManager);
  // 讀取JS Bundle裡的內容
  auto script = loadScriptFromAssets(manager, sourceURL);
  // unbundle命令打包判斷
  if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
    instance_->loadUnbundle(
      folly::make_unique<JniJSModulesUnbundle>(manager, sourceURL),
      std::move(script),
      sourceURL,
      loadSynchronously);
    return;
  } else {
    //bundle命令打包走次流程,instance_Instan.h中類的例項
    instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
  }
}

Instance.cpp

void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,
                                    std::string sourceURL,
                                    bool loadSynchronously) {
  SystraceSection s("reactbridge_xplat_loadScriptFromString", "sourceURL", sourceURL);
  if (loadSynchronously) {
    loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));
  } else {
    loadApplication(nullptr, std::move(string), std::move(sourceURL));
  }
}

void Instance::loadApplicationSync(
    std::unique_ptr<JSModulesUnbundle> unbundle,
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL) {
  std::unique_lock<std::mutex> lock(m_syncMutex);
  m_syncCV.wait(lock, [this] { return m_syncReady; });

  SystraceSection s("reactbridge_xplat_loadApplicationSync", "sourceURL", sourceURL);
  //nativeToJsBridge_也是在Instance::initializeBridget()方法裡初始化的,具體實現在NativeToJsBridge.cpp裡。
  nativeToJsBridge_->loadApplicationSync(std::move(unbundle), std::move(string), std::move(sourceURL));
}

NativeToJsBridge.cpp

void NativeToJsBridge::loadApplication(
    std::unique_ptr<JSModulesUnbundle> unbundle,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {

  //獲取一個MessageQueueThread,探後線上程中執行一個Task。
  runOnExecutorQueue(
      m_mainExecutorToken,
      [unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),
       startupScript=folly::makeMoveWrapper(std::move(startupScript)),
       startupScriptSourceURL=std::move(startupScriptSourceURL)]
        (JSExecutor* executor) mutable {

    auto unbundle = unbundleWrap.move();
    if (unbundle) {
      executor->setJSModulesUnbundle(std::move(unbundle));
    }

    //executor從runOnExecutorQueue()返回的map中取得,與OnLoad中的JSCJavaScriptExecutorHolder對應,也與
    //Java中的JSCJavaScriptExecutor對應。它的例項在JSExecutor.cpp中實現。
    executor->loadApplicationScript(std::move(*startupScript),
                                    std::move(startupScriptSourceURL));
  });
}

關於unbundle命令

<unbundle命令,使用方式和bundle命令完全相同。unbundle命令是在bundle命令的基礎上增加了一項功能,除了生成整合JS檔案index.android.bundle外,還會
生成各個單獨的未整合JS檔案(但會被優化),全部放在js-modules目錄下,同時會生成一個名為UNBUNDLE的標識檔案,一併放在其中。UNBUNDLE標識檔案的前4個位元組
固定為0xFB0BD1E5,用於載入前的校驗。

該函式進一步呼叫JSExecutor.cpp的loadApplicationScript()方法。

到了這個方法,就是去真正載入JS檔案了。

JSCExecutor.cpp

void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) {

    ...
    //使用Webkit JSC去解釋執行JS
    evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
    flush();
}
void JSCExecutor::flush() {
    ...
    //繫結bridge,核心就是通過getGlobalObject()將JS與C++通過Webkit jSC實現繫結
      bindBridge();
      //返回給callNativeModules
    callNativeModules(m_flushedQueueJS->callAsFunction({}));
    ...
}
void JSCExecutor::callNativeModules(Value&& value) {
    ...
    //把JS層相關通訊資料轉換為JSON格式
    auto calls = value.toJSONString();
    //m_delegate為JsToNativeBridge物件。
    m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
    ...
}

m_flushedQueueJS支線的是MessageQueue.js的flushedQueue()方法,此時JS已經被載入到佇列中,等待Java層來驅動它。

JS Bundle載入並解析完成後,我們回到Java程式碼中看看後續的流程

我們在之前的runCreateReactContextOnNewThread方法中,在creatReactContext之後還有一句核心的程式碼

setupReactContext(reactApplicationContext);

這就是載入JS Bundle之後執行的程式碼

public class ReactInstanceManager {
    private void setupReactContext(ReactApplicationContext reactContext) {
        ...
        // Native Java module初始化
    catalystInstance.initialize();
    //重置ReactContext 
    mDevSupportManager.onNewReactContextCreated(reactContext);
   //記憶體狀態回撥設定 mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
    // 復位生命週期
    moveReactContextToCurrentLifecycleState();

    ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
    synchronized (mAttachedRootViews) {
    //mAttachedRootViews儲存的是ReactRootView
      for (ReactRootView rootView : mAttachedRootViews) {
        attachRootViewToInstance(rootView, catalystInstance);
      }
    }
    ...
    }
}

private void attachMeasuredRootViewToInstance (     final ReactRootView rootView,
      CatalystInstance catalystInstance) {
      ...
            //將ReactRootView作為根佈局
    UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
    int rootTag = uiManagerModule.addMeasuredRootView(rootView);
    //設定相關
    rootView.setRootViewTag(rootTag);
    rootView.runApplication();
    ...
      }
  /* package */ void runApplication() {
        ...
      CatalystInstance catalystInstance = reactContext.getCatalystInstance();

      WritableNativeMap appParams = new WritableNativeMap();
      appParams.putDouble("rootTag", getRootViewTag());
      @Nullable Bundle appProperties = getAppProperties();
      if (appProperties != null) {
        appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
      }

      String jsAppModuleName = getJSModuleName();
      //啟動流程入口:由Java層呼叫啟動
      catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
      ...
  }

可以看到,最終呼叫的是catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams), AppRegistry.class是JS層暴露給Java層的介面方法。它的真正實現在AppRegistry.js裡,AppRegistry.js是執行所有RN應用的JS層入口,我們來看看它的實現:

Libraries/ReactNative中的AppRegistry.js

AppRegistry.js

  runApplication(appKey: string, appParameters: any): void {
    const msg =
      'Running application "' + appKey + '" with appParams: ' +
      JSON.stringify(appParameters) + '. ' +
      '__DEV__ === ' + String(__DEV__) +
      ', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') +
      ', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON');
    infoLog(msg);
    BugReporting.addSource('AppRegistry.runApplication' + runCount++, () => msg);
    invariant(
      runnables[appKey] && runnables[appKey].run,
      'Application ' + appKey + ' has not been registered.\n\n' +
      'Hint: This error often happens when you\'re running the packager ' +
      '(local dev server) from a wrong folder. For example you have ' +
      'multiple apps and the packager is still running for the app you ' +
      'were working on before.\nIf this is the case, simply kill the old ' +
      'packager instance (e.g. close the packager terminal window) ' +
      'and start the packager in the correct app folder (e.g. cd into app ' +
      'folder and run \'npm start\').\n\n' +
      'This error can also happen due to a require() error during ' +
      'initialization or failure to call AppRegistry.registerComponent.\n\n'
    );

    SceneTracker.setActiveScene({name: appKey});
    runnables[appKey].run(appParameters);
  },

到這裡就會去呼叫JS進行渲染,在通過UIManagerModule將JS元件轉換成Android元件,最終顯示在ReactRootView上。

最後總結一下,就是先在應用終端啟動並建立上下文物件,啟動JS Runtime,進行佈局,將JS端的程式碼通過C++層,UIManagerMoodule轉化成Android元件,再進行渲染,最後將渲染的View新增到ReactRootView上,最終呈現在使用者面前。

如果還是不太懂的話,可以看下大佬們畫的圖

ReactNative系統框架圖如下所示

啟動流程圖:

參考資料

相關推薦

react-native 啟動流程原理解析

前言 專案中用到RN也有一段時間了, 從剛開始的懵懂到現在的熟能生巧,其實還是很長的,每次接觸一個新的東西的時候,剛開始一定是比較痛苦的,不知道要如何下手,這裡從js到Android原生去一步步解析React Native是如何做到如此巧妙的通訊的。希望能

SpringBoot啟動流程原理解析(二)

>在上一章我們分析了SpingBoot啟動流程中例項化SpingApplication的過程。 `return new SpringApplication(primarySources).run(args);` 這篇文章咱麼說下`run()`方法開始之後都做了那些事情。 繼續往下跟著原始碼進入到`run()

知識儲備:SpringBoot啟動執行流程原理解析

SpringBoot專案通過SpringApplication.run()執行,分為兩步 首先new了一個SpringApplication,之後再呼叫run()方法 ,下面我們就看看這兩步 1.建立SpringApplication 通過debug進入到Sprin

react-native App的原理介紹

nat image prop 效果 沒有 結構 內部 div 單向 react-native App中,大體可以理解為:整個APP作為容器,裏面存放有多個父組件,子組件,孫子組件,各個組件都含有state和props這兩個最重要的屬性. 如下圖所示: React 有pro

Android中system server程序啟動流程原始碼解析 系統服務啟動

system server 前言 System Server fork SystemServer SystemServer.main() SystemServer.createSystemContext SystemSe

React 服務器渲染原理解析與實踐

情況下 修正 下載地址 pro 以及 解決 問題 為什麽 ack 第1章 服務器端渲染基礎本章主要講解客戶端與服務器端渲染的概念,分析客戶端渲染和服務器端渲染的利弊,帶大家對服務器端渲染有一個粗淺認識。 1-1 課程導學1-2 什麽是服務器端渲染1-3 什麽是客戶端渲染1-

Spring boot啟動流程原始碼解析

閱讀須知 版本:2.0.4 文章中使用/* */註釋的方法會做深入分析 正文 @SpringBootApplication public class BootApplication { public static void main(String[

react-native 啟動頁設定(ios)

使用第三方外掛:react-native-splash-screen 下載地址:https://www.npmjs.com/package/react-native-splash-screen 第一步:安裝下載外掛 1、npm i react-native-splash-screen -

react-native 啟動頁設定(android)

使用第三方外掛:react-native-splash-screen 下載地址:https://www.npmjs.com/package/react-native-splash-screen 第一步:安裝下載外掛 1、npm i react-native-splash-screen

Spring IOC容器啟動流程原始碼解析(一)——容器概念詳解及原始碼初探

目錄 1. 前言 1.1 IOC容器到底是什麼 IOC和AOP是Spring框架的核心功能,而IOC又是AOP實現的基礎,因而可以說IOC是整個Spring框架的基石。那麼什麼是IOC?IOC即控制反轉,通俗的說就是讓Spring框架來幫助我們完成物件的依賴管理和生命週期控制等等工作。從面向物件的角度來說,

react-native 啟動的時候報錯unable to load script from assets 'index.android bundle'

實行命令react-native run-android報以下錯誤 unable to load script from assets 'index.android bundle'  ,make sure your bundle is packaged correctly or y

Spring IOC容器啟動流程原始碼解析(四)——初始化單例項bean階段

目錄 1. 引言 2. 初始化bean的入口 3 嘗試從當前容器及其父容器的快取中獲取bean 3.1 獲取真正的beanName 3.2 嘗試從當前容器的快取中獲取bean 3.3 從父容器中查詢bean 3.4 解析bean的依賴 3.5 再一

Android Activity的啟動流程原始碼解析(8.0)

一,寫在前面        Activity是Android四大元件之一,用於直接跟使用者進行互動,本篇文章將介紹Activity的啟動流程。使用者啟動Activity的方式大致有兩種:一種是在桌面點選應用程式的圖示,進入應用程式的主介面;另一種是在應用程式中,進入一個新的

react-native啟動android service bug解決辦法

react-native與android原生互動啟動service,裡面寫了個定時任務,退出登入後重新登入,程式竟然崩潰了?!好坑啊~檢視崩潰日誌發現,報以下錯誤:java.lang.IllegalStateException: TimerTask is sch

react-native 啟動的時候報錯unable to load script from assets 'index.android bundle'

實行命令react-native run-android報以下錯誤 unable to load script from assets 'index.android bundle'  ,make su

React Native 啟動白屏問題解決方案,教程

問題描述: 用React Native架構的無論是Android APP還是iOS APP,在啟動時都出現白屏現象,時間大概1~3s(根據手機或模擬器的效能不同而不同)。 問題分析: 為什麼會產生白屏? React Native應用在啟動時會將js bundle

react-native-art path程式碼解析

React-Native-ART程式碼解析 一、探尋原始碼 1.如何使用 安卓自己整合,不需要額外操作,iOS需要pod新增ART庫,如下: pod 'React', :path => '../rn-source', :subspecs =

NioEventLoop啟動流程原始碼解析

NioEventLoop的啟動時機是在服務端的NioServerSocketChannel中的ServerSocketChannel初始化完成,且註冊在NioEventLoop後執行的, 下一步就是去繫結埠,但是在繫結埠前,需要完成NioEventLoop的啟動工作, 因為程式執行到這個階段為止,依然只有Ma

SpringSecurity啟動流程原始碼解析 | 部落格園新人第三彈

別辜負生命,別辜負自己。 楔子 前面兩期我講了SpringSecurity認證流程和SpringSecurity鑑權流程,今天是第三期,是SpringSecurity的收尾工作,講SpringSecurity的啟動流程。 就像很多電影拍火了之後其續作往往是前作的前期故事一樣,我這個第三期要講的Sprin

React Native執行原理解析

Facebook 於2015年9月15日推出react native for Android 版本, 加上2014年底已經開源的IOS版本,至此RN (react-native)真正成為跨平臺的客戶端框架。本篇主要是從分析程式碼入手,探討一下RN在安卓平臺上是如何構建一套JS