You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactApplication.javapackagecom.facebook.react;
publicinterfaceReactApplication {
/** Get the default {@link ReactNativeHost} for this app. */ReactNativeHostgetReactNativeHost();
}
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java// ...publicclassReactRootViewextendsFrameLayoutimplementsRootView, ReactRoot {
// ...publicvoidstartReactApplication(
ReactInstanceManagerreactInstanceManager,
StringmoduleName,
@NullableBundleinitialProperties,
@NullableStringinitialUITemplate) {
// ...try {
// 断言:如果当前线程不是 UI 线程的话,就会抛出 Expected to run on UI thread! 的错误UiThreadUtil.assertOnUiThread();
Assertions.assertCondition(
mReactInstanceManager == null,
"This root view has already been attached to a catalyst instance manager");
// 赋值mReactInstanceManager = reactInstanceManager;
mJSModuleName = moduleName;
mAppProperties = initialProperties;
mInitialUITemplate = initialUITemplate;
// mUseSurface 是在构造函数中被赋值的 if (mUseSurface) {
// TODO initialize surface here
}
/** * 在后台任务中触发 react context 的初始化(异步) * 此时会去预加载 js,并在 UI 的布局完成之前执行全局代码 */mReactInstanceManager.createReactContextInBackground();
// 将 RootView 附加到 ReactInstanceManager 的成员变量 mAttachedReactRoots 中// 后文会再提到 mAttachedReactRootsattachToReactInstanceManager();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
// ...
}
接下来我们看 ReactInstanceManager 对应代码的实现。
ReactInstanceManager
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java// ...publicvoidcreateReactContextInBackground() {
//略去日志输出代码// UI 线程断言UiThreadUtil.assertOnUiThread();
// 是否已经初始化的判断if (!mHasStartedCreatingInitialContext) {
mHasStartedCreatingInitialContext = true;
recreateReactContextInBackgroundInner();
}
}
/** * Recreate the react application and context. This should be called if configuration has changed * or the developer has requested the app to be reloaded. It should only be called after an * initial call to createReactContextInBackground. */@ThreadConfined(UI)
publicvoidrecreateReactContextInBackground() {
// ...recreateReactContextInBackgroundInner();
}
// ...
前言
第一次接触 React Native 是在四年前实习的时候,当时在项目中使用的 RN 版本是
0.28.x
,间隔四年之后,再次在项目中使用 RN 时版本已是0.57.x
。在撰写本文时,RN 的版本是0.60.4
,所以,本文将以0.60.4
版本为基础,简要分析 RN 应用在 Android 平台上的启动流程。Hello World
用 RN 来写一个 Hello World 应用非常简单。通过 RN cli 生成项目之后,更改程序的入口文件即可:
程序的入口文件一般是通过
AppRegistry
对 RN 应用进行注册,registerComponent
的实现如下:registerComponent
方法的第一个参数是appKey
,第二个参数是与之对应的根组件。因而如果要注册多个 RN 应用,就需要确保appKey
的值是唯一的,因为原生端也是依赖appKey
来启动对应的 RN 应用的。那么,在 JavaScript 端注册
HelloWorld
应用之后,原生端是怎么启动HelloWorld
的呢?启动流程
通过 RN cli 新建
Hello
项目之后,不仅会生成 JavaScript 代码,也会创建与之对应的原生工程项目。对于 Android 工程而言,会生成两个主要的类:MainActivity
和MainApplication
,这是 Android 应用的启动入口。先看下
MainActivity
的实现:MainActivity
继承了ReactActivity
,并重写了getMainComponentName
方法,而这个方法就是返回在 JavaScript 端注册的appKey
。然后再看下
MainApplication
的实现:MainApplication
实现了接口ReactApplication
,主要是实现其getReactNativeHost
方法:ReactNativeHost
是 RN 应用的宿主类,其本身是一个抽象类,在创建ReactNativeHost
实例时,重写了里面的两个抽象方法:虽然在
ReactDelegate#loadApp
方法被调用时才创建ReactInstanceManager
实例,但我们简单看下其创建的参数列表,这有利于后文的理解。ReactInstanceManagerBuilder#build
方法的实现如下:重点需要关注两点:
mJSBundleLoader
的初始化:JSBundleLoader
是一个抽象类,但根据不同的 bundle 加载场景,提供了不同的静态方法来创建匿名子类实例。上文说到,可以通过重写ReactNativeHost#getJSBundleFile
方法自定义 bundle 的加载路径。如果 bundle 路径不是以assets://
开头,则会通过JSBundleLoader
类的静态方法createFileLoader
创建一个实例;反之,则会通过其静态方法createAssetLoader
创建一个实例。mJavaScriptExecutorFactory
的初始化:通过上文可知,ReactNativeHost#getJavaScriptExecutorFactory
返回值是null
,因而会调用getDefaultJSExecutorFactory
方法创建默认的 js 执行器工厂实例。接下来看看
ReactActivity
的实现。ReactActivity
从上文可知,
MainActivity
继承了ReactActivity
,并重写了getMainComponentName
方法。ReactActivity
是一个抽象类,其主要实现如下:ReactActivity
本身是一个抽象类,没有具体的功能实现,其主要作用有两个:getMainComponentName
方法的声明ReactActivityDelegate
实例,便于把具体的功能全委托给ReactActivityDelegate
类来处理ReactActivityDelegate
ReactActivityDelegate
类的主要实现如下:ReactActivityDelegate
类主要是在其生命周期的onCreate
方法中做了三件事:创建ReactDelegate
实例、调用ReactActivityDelegate#loadApp
开始启动 RN 应用以及设置当前 Activity 的根视图。ReactDelegate
ReactDelegate
类的实现比较简单,关键部分代码如下:ReactDelegate#loadApp
方法主要做了两件事:创建 RootView 和开始启动 React App。ReactRootView
ReactRootView
是一个自定义的 View,其父类是FrameLayout
,代码量比较大,因而我们只顺着上面的思路看一下startReactApplication
的实现:接下来我们看
ReactInstanceManager
对应代码的实现。ReactInstanceManager
从代码中可以看到,
createReactContextInBackground
在 Application 中只会被调用一次。当应用配置或者应用重新加载时,需要重新创建 ReactContext 信息,此时是去调用公开的recreateReactContextInBackground
方法(注意:该方法有一个私有的实现,后续会提到)。但两个方法最终调用的实际都是recreateReactContextInBackgroundInner
方法:recreateReactContextInBackground
方法的私有实现中,有两个形参:jsExecutorFactory
和jsBundleLoader
:接着往下看
runCreateReactContextOnNewThread
的实现:runCreateReactContextOnNewThread
方法的核心是调用createReactContext
方法来创建 React Context:createReactContext
方法主要作了如下四件事:CatalystInstance
是一个接口类型,定义了一系列 JSC(JavaScript Core) Bridge API 接口,提供了允许(从 Java 层)调用 JS 方法的环境,同时提供了部分 Java API 供 JS 层调用,其具体实现是CatalystInstanceImpl
类。下一篇我们继续接着分析
CatalystInstanceImpl
类。The text was updated successfully, but these errors were encountered: