ReactNative启动流程详细解析
导读:本⽂以react-native-cli创建的⽰例⼯程(安卓部分)为例,分析 React Native 的启动流程。
⼯程创建步骤可以参考。本⽂所分析React Native版本为v0.64.2。
我们知道上述⼯程是⼀个安卓应⽤,打开android/⽬录下源码⽂件,⾸先发现它创建了两个 java ⽂件: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> packages = new PackageList(this).getPackages();
// 其它对 packages 的操作
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
}
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
MainApplication继承⾃ Application 类,并且实现了ReactApplication接⼝。在其中做的事情有:
1.创建成员变量ReactNativeHost的实例,并在创建过程中通过重写 ReactNativeHost 类⽅法的⽅式,注⼊⼀些配置,包括:
1. getUseDeveloperSupport: 配置是否开启调试
2. getPackages: 配置要加载的模块
3. getJSMainModuleName: 配置 js 模块的⼊⼝⽂件名
2.在 onCreate 中:
1. 调⽤ Soloader 库。Soloader是 facebook 推出的⼀个 so ⽂件加载库,它能够处理 so ⽂件的依赖在 react-native 中,所有
框架相关的 so ⽂件都是通过SoLoader完成加载的
2. 通过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) {
}
ReactActivity全权委托给ReactActivityDelegate来处理onCreate⽣命周期。来看ReactActivityDelegate的onCreate。
protected void onCreate(Bundle savedInstanceState) {
String mainComponentName = getMainComponentName();
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
@Override
protected ReactRootView createRootView() {
return ateRootView();
}
};
if (mMainComponentName != null) {
loadApp(mainComponentName);
}
}
这⾥⾸先创建了 ReactDelegate 实例。接着来看loadApp⽅法:
protected void loadApp(String appKey) {
mReactDelegate.loadApp(appKey);
getPlainActivity().ReactRootView());
}
由此⾛到ReactDelegate实例的loadApp⽅法:
public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
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 {
reactnative开发builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
ReactInstanceManager reactInstanceManager = builder.build();
return reactInstanceManager;
}
此处做的事情如下:
创建ReactInstanceManagerBuilder实例。这⾥采⽤建造者模式来构造ReactInstanceManager实例,故在此先传⼊参数设定构造者;
把在ReactNativeHost中注册的packages都添加到ReactInstanceManagerBuilder实例中;
如果getJSBundleFile不为空,则加载对应的⽂件,否则加载默认的jsBundleFile;
调⽤builder.build⽅法。通过建造者真正构造ReactInstanceManager实例
startReactApplication
public void startReactApplication(/* */) {
// ...
try {
// ...
} finally {
// ...
}
}
最终执⾏到ReactInstanceManager的createReactContextInBackground⽅法中。最后经过调⽤链:recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread() runCreateReactContextOnNewThread主要做了两件事:
1. 创建⼀个新的线程,并在新线程中通过createReactContext创建ReactContext上下⽂;
2. 通过setupReactContext来设置上下⽂环境,并最终调⽤到AppRegistry.js启动App。
详细分析我们放到另⼀篇⽂章:。
总结
总结本⽂,通过react-native-cli创建的⽰例⼯程(安卓部分)为例,顺着两个类MainApplication和MainActivity的执⾏流程,抓住主⼲逻辑,最终梳理出了React Native从开始启动⾄执⾏⽤户js⽂件的过程。可以看到:
MainApplication的作⽤主要是传⼊⽤户的配置,并做so库以及应⽤debug⼯具的初始化⼯作;
MainActivity的作⽤主要是:
1. 为应⽤创建rootView布局容器;
2. 创建ReactInstanceManager核⼼类,⽤于后续管理 JS 的加载、C++ 和 JS 的交互、初始化参数等;
3. 通过startReactApplication来创建ReactContext上下⽂,并最终调⽤到AppRegistry.js启动App。
到此这篇关于React Native 启动流程简析的⽂章就介绍到这了,更多相关React Native 启动内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论