React Native 啟動流程詳細解析
導讀:本文以 react-native-cli
建立的示例工程(安卓部分)為例,分析 React Native 的啟動流程。
工程建立步驟可以參考官網。本文所分析 React Native
版本為 v0.64.2
。
我們知道上述工程是一個安卓應用,開啟 /
目錄下原始碼檔案,首先發現它建立了兩個 檔案:MainApplication.java
和 MainActivity.java
,分別做了應用以及主 Activity 的定義。
安卓應用的啟動流程是:在啟動第一個 activity
之前會建立一個全域性唯一的 Application
物件。故在此我們先分析 MainApplication
MainApplication
public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List<ReactPackage> pacGhUTKRoeHCkages = new PackageList(this).getPackages(); // 其它對 packages 的操作 return packages; } @Override protected String getMainModuleName() { return "index"; } } @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this,/* native exopackage */ false); initializeFlipper(this,getReactNativeHost().getReactInstanceManager()); }
MainApplication
繼承自 Application 類,並且實現了 ReactApplication
介面。在其中做的事情有:
1.建立成員變數 ReactNativeHost
的例項,並在建立過程中通過重寫 ReactNativeHost 類方法的方式,注入一些配置,包括:
- getUseDeveloperSupport: 配置是否開啟除錯
- getPackages: 配置要載入的模組
- getJSMainModuleName: 配置 js 模組的入口檔名
2.在 onCreate 中:
- 呼叫 Soloader 庫。
Soloader
是 facebook 推出的一個 so 檔案載入庫,它能夠處理 so 檔案的依賴在 react-native 中,所有框架相關的 so 檔案都是通過SoLoader完成載入的
www.cppcns.com - 通過
ReactInstanceManager
初始化 Flipper。Flipper
是 facebook 推出的用於 debug ios、Android、React Native 應用的工具。
在這裡簡要介紹下 ReactNativeHost
和 ReactInstanceManager
ReactNativeHost
ReactNativeHost
是個抽象類,開發者可以重寫其中的方法,其主要的作用是:在 application 中指定一些賦值操作,進而獲取 ReactInstanceManager
的例項。所以可以把 ReactNativeHost
作為將使用者自定義的引數賦值到 ReactInstanceManager
例項的中轉站。核心方法是: getReactInstanceManager
,詳細分析見下文。
ReactInstanceManager
該類為核心類,主要負責管理 JS 的載入、維護生命週期、管理 JS 與 C++ 的互動等等。可以把 ReactInstanceManager
理解成 JS 與 C++ 的中轉橋樑。
MainActivity
接著看 MainActivity.java
:
public class MainActivity extends ReactActivity { @Override protected String getMainComponentName() { return "myProject"; } }
MainActivity
類中僅重寫了 getMainComponentName 方法。該類繼承自 ReactActivity
,我們再來看其 ReactActivity
。
public abstract class ReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler,PermissionAwareActivity { private final ReactActivityDelegate mDelegate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDelegate.onCreate(savedInstanceState); }
ReactActivity
全權委託給 ReactActivityDelegate
來處理 onCreate
生命週期。來看 ReactActivityDelegate
的 onCreate
。
protected void onCreate(Bundle savedInstanceState) { String mainComponentName = getMainComponentName(); mReactDelegate = new ReactDelegate( getPlainActivity(),getReactNativeHost(),mainComponentName,getLaunchOptions()) { @Override www.cppcns.com protected ReactRootView createRootView() { return ReactActivityDelegate.this.createRootView(); } }; if (mMainComponentName != null) { loadApp(mainComponentName); } }
這裡首先建立了 ReactDelegate 例項。接著來看 loadApp
方法:
protected void loadApp(String appKey) { mReactDelegate.loadApp(appKey); getPlainActivity().setContentView(mReactDelegate.getReactRootView()); }
由此走到 ReactDelegate
例項的 loadApp
方法:
public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.GhUTKRoeHC");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),appKey,mLaunchOptions);
}
在這裡做了三件事:建立 rootView (createRootView
)、建立 ReactInstanceManager (getReactInstanceManager
)、建立 ReactApplication (startReactApplication
)。
createRootView
首先看下什麼是 rootView。
public class ReactRootView extends FrameLayout implements RootView,ReactRoot { /* ... */}
ReactRootView 繼承自 FrameLayout
,並且實現了 RootView
、ReactRoot
兩個介面。FrameLayout
是安卓幾大佈局中較為簡單的一個,整個介面被當成一塊空白備用區域,所有元素以左上角對齊堆疊。ReactRootView 繼承自 FrameLayout
,表明其也是作為簡單佈局而存在,UI 的繪製渲染
都發生在上面。
getReactInstanceManager
ReactInstanceManager
是一個核心類,管理著 JS 的載入、C++ 和 JS 的互動、初始化引數等。最終呼叫來到 ReactNativeHost
類中的 createReactInstanceManager
方法:
protected ReactInstanceManager createReactInstanceManager() {
ReactInstanceManagerBuilder builder = /* ... */
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())http://www.cppcns.com);
}
ReactInstanceManager reactInstanceManager = builder.build();
return reactInstanceManager;
}
此處做的事情如下:
- 建立
ReactInstanceManagerBuilder
例項。這裡採用建造者模式來構造ReactInstanceManager
例項,故在此先傳入引數設定構造者; - 把在
ReactNativeHost
中註冊的packages
都新增到ReactInstanceManagerBuilder
例項中; - 如果
getJSBundleFile
不為空,則載入對應的檔案,否則載入預設的jsBundleFile
; - 呼叫
builder.build
方法。通過建造者真正構造ReactInstanceManager
例項
startReactApplication
public void startReactApplication(/* */) { // ... try { // ... mReactInstanceManager.createReactContextInBackground(); } finally { // ... } }
最終執行到 ReactInstanceManager
的 createReactContextInBackground
方法中。最後經過呼叫鏈:recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()
runCreateReactContextOnNewThread
主要做了兩件事:
- 建立一個新的執行緒,並在新執行緒中通過
createReactContext
建立ReactContext
上下文; - 通過
setupReactContext
來設定上下文環境,並最終呼叫到AppRegistry.js
啟動App。
詳細分析我們放到另一篇文章:React Native startReactApplication 流程梳理。
總結
總結本文,通過 react-native-cli
建立的示例工程(安卓部分)為例,順著兩個類 MainApplication
和 MainActivity
的執行流程,抓住主幹邏輯,最終梳理出了 React Native
從開始啟動至執行使用者 js
檔案的過程。可以看到:
MainApplication
的作用主要是傳入使用者的配置,並做 so
庫以及應用 debug
工具的初始化工作;
MainActivity
的作用主要是:
- 為應用建立
rootView
佈局容器; - 建立
ReactInstanceManager
核心類,用於後續管理 JS 的載入、C++ 和 JS 的互動、初始化引數等; - 通過
startReactApplication
來建立ReactContext
上下文,並最終呼叫到AppRegistry.js
啟動App。
到此這篇關於React Native 啟動流程簡析的文章就介紹到這了,更多相關React Native 啟動內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!