一、前言
???????好吧,其實(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)如下
在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