Description
前言
第一次接触 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 生成项目之后,更改程序的入口文件即可:
import { Text, AppRegistry } from 'react-native'
import App from './App'
// ...
AppRegistry.registerComponent('HelloWorld', () => App);
程序的入口文件一般是通过 AppRegistry
对 RN 应用进行注册,registerComponent
的实现如下:
// react-native/Libraries/ReactNative/AppRegistry.js
// ...
// 类型声明
export type ComponentProvider = () => React$ComponentType<any>;
export type Runnable = {
component?: ComponentProvider,
run: Function,
};
export type Runnables = {
[appKey: string]: Runnable,
};
// 保存注册过的应用
const runnables: Runnables = {};
// ...
// 注册应用的根组件
registerComponent(
appKey: string,
componentProvider: ComponentProvider,
section?: boolean,
): string {
runnables[appKey] = {
componentProvider,
/**
* appParameters 是原生端初始化 RN 应用时透传的参数
* 属性主要包含用于初始化的 initialProps,rootTag,fabric等
*/
run: appParameters => {
renderApplication(
// ...
)
},
};
// ...
return appKey;
},
// ...
registerComponent
方法的第一个参数是 appKey
,第二个参数是与之对应的根组件。因而如果要注册多个 RN 应用,就需要确保 appKey
的值是唯一的,因为原生端也是依赖 appKey
来启动对应的 RN 应用的。
那么,在 JavaScript 端注册 HelloWorld
应用之后,原生端是怎么启动 HelloWorld
的呢?
启动流程
通过 RN cli 新建 Hello
项目之后,不仅会生成 JavaScript 代码,也会创建与之对应的原生工程项目。对于 Android 工程而言,会生成两个主要的类: MainActivity
和 MainApplication
,这是 Android 应用的启动入口。
先看下 MainActivity
的实现:
// ...
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "HelloWorld";
}
}
MainActivity
继承了 ReactActivity
,并重写了 getMainComponentName
方法,而这个方法就是返回在 JavaScript 端注册的 appKey
。
然后再看下 MainApplication
的实现:
// ...
public class MainApplication extends Application implements ReactApplication {
// 创建 ReactNativeHost 的匿名子类实例
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
// 是否开启 dev mode
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
/**
* 返回原生依赖的包列表
* 实际开发中,js 端会对原生端有依赖,当原生端把依赖暴露给 RN 时,需要在这手动添加原生包
* 在后续的流程中,会把所有的原生依赖在 C++ 层进行注册,供 js 端调用
* packages.add(new MyReactNativePackage())
*/
return packages;
}
@Override
protected String getJSMainModuleName() {
// 返回主模块名,默认为 index
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
/**
* 初始化 Soloader(https://github.com/facebook/SoLoader)
* 在一个 RN 应用中,牵涉到 js 和 Native(C/C++) 的通信(JSC/JSI),Java 和 Native(C/C++) 的通信(JNI)
* 以及 js 和 Java 之间的通信(转嫁到 C++ 上)
* 而 Soloader 就是一个 Native Code(主要是c/c++) 的 loader,用于加载和解析动态链接库,为后续的通信作准备
*/
SoLoader.init(this, /* native exopackage */ false);
}
}
MainApplication
实现了接口 ReactApplication
,主要是实现其 getReactNativeHost
方法:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactApplication.java
package com.facebook.react;
public interface ReactApplication {
/** Get the default {@link ReactNativeHost} for this app. */
ReactNativeHost getReactNativeHost();
}
ReactNativeHost
是 RN 应用的宿主类,其本身是一个抽象类,在创建 ReactNativeHost
实例时,重写了里面的两个抽象方法:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java
// ...
public abstract class ReactNativeHost {
private final Application mApplication;
private @Nullable ReactInstanceManager mReactInstanceManager;
protected ReactNativeHost(Application application) {
// 保存 app 应用实例
mApplication = application;
}
/**
* 返回 ReactInstanceManager 实例
* 这个方法会在 ReactDelegate#loadApp 方法中被调用
* 其返回值赋值给 ReactRootView#startReactApplication 方法的第一个参数
*/
public ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceManager == null) {
// 略去日志代码
// 实例不存在则创建实例
mReactInstanceManager = createReactInstanceManager();
// 略去日志代码
}
return mReactInstanceManager;
}
// ...
// 创建 ReactInstanceManager 实例
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
/**
* 类 ReactInstanceManagerBuilder 提供了很多 set 方法来保存创建
* ReactInstanceManager 实例相关的上下文信息
*/
ReactInstanceManagerBuilder builder =
ReactInstanceManager.builder()
// 应用上下文
.setApplication(mApplication)
// 设置MainModuleName,相当于应用首页的 js bundle
.setJSMainModulePath(getJSMainModuleName())
// 是否开启dev模式
.setUseDeveloperSupport(getUseDeveloperSupport())
// 设置红盒的回调(dev 模式下才有红屏显示)
.setRedBoxHandler(getRedBoxHandler())
// 设置 js 的执行器工厂实例,为后续加载和解析 js bundle 作准备
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
// 设置UI实现机制的Provider
.setUIImplementationProvider(getUIImplementationProvider())
// 设置 JSI Module:js -->C++(JSI)-->Java Module
.setJSIModulesPackage(getJSIModulePackage())
// 初始化 host 的生命周期状态
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
// 添加原生依赖包
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
/**
* 获取js Bundle的加载路径
* 如果没有自定义加载路径,就从 Android assets 中加载 index.android.bundle 文件
* 默认路径是:assets:// + getBundleAssetName 方法的返回值
*/
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
// 根据上面设置的一系列参数去创建 ReactInstanceManager 实例
ReactInstanceManager reactInstanceManager = builder.build();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
}
// RedBox 相关的回调
protected @Nullable RedBoxHandler getRedBoxHandler() {
return null;
}
// 如果要自定义 js 执行器,重写该方法
protected @Nullable JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
return null;
}
protected final Application getApplication() {
return mApplication;
}
// 如果需要自定义UI实现机制,可重写该方法,但99%的情况下不需要,使用默认机制就行
protected UIImplementationProvider getUIImplementationProvider() {
return new UIImplementationProvider();
}
protected @Nullable JSIModulePackage getJSIModulePackage() {
return null;
}
/**
* 返回主模块名
* 返回值决定了从服务器拉取 js bundle 的 URL,仅在开发模式下有用
*/
protected String getJSMainModuleName() {
return "index.android";
}
/**
* 返回 js bundle 文件的路径
* 如果需要自定义路径,需要在子类中重写这个方法
* 默认会从 Android assets 中加载 js bundle
* 文件路径类似于 "file://sdcard/myapp_cache/index.android.bundle"
*/
protected @Nullable String getJSBundleFile() {
return null;
}
// 返回 Android assets 中的 js bundle 名称
protected @Nullable String getBundleAssetName() {
return "index.android.bundle";
}
// 是否开启dev模式
public abstract boolean getUseDeveloperSupport();
// 返回app需要的ReactPackage,包含了运行时需要用到的NativeModule/JavaScriptModule等
protected abstract List<ReactPackage> getPackages();
}
虽然在 ReactDelegate#loadApp
方法被调用时才创建 ReactInstanceManager
实例,但我们简单看下其创建的参数列表,这有利于后文的理解。
ReactInstanceManagerBuilder#build
方法的实现如下:
// react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
// ...
import static com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getFriendlyDeviceName;
// ...
public ReactInstanceManager build() {
// ...
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,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
? getDefaultJSExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
mJSMainModulePath,
mPackages,
mUseDeveloperSupport,
mBridgeIdleDebugListener,
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
mUIImplementationProvider,
mNativeModuleCallExceptionHandler,
mRedBoxHandler,
mLazyViewManagersEnabled,
mDevBundleDownloadListener,
mMinNumShakes,
mMinTimeLeftInFrameForNonBatchedOperationMs,
mJSIModulesPackage,
mCustomPackagerCommandHandlers);
}
private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName) {
try {
// 加载 C++ 层的 jscexecutor,优先考虑使用 JSC 引擎
SoLoader.loadLibrary("jscexecutor");
return new JSCExecutorFactory(appName, deviceName);
} catch (UnsatisfiedLinkError jscE) {
// JSC 加载失败,就使用 Hermes 引擎
return new HermesExecutorFactory();
}
}
// ...
重点需要关注两点:
-
mJSBundleLoader
的初始化:JSBundleLoader
是一个抽象类,但根据不同的 bundle 加载场景,提供了不同的静态方法来创建匿名子类实例。上文说到,可以通过重写ReactNativeHost#getJSBundleFile
方法自定义 bundle 的加载路径。如果 bundle 路径不是以assets://
开头,则会通过JSBundleLoader
类的静态方法createFileLoader
创建一个实例;反之,则会通过其静态方法createAssetLoader
创建一个实例。 -
mJavaScriptExecutorFactory
的初始化:通过上文可知,ReactNativeHost#getJavaScriptExecutorFactory
返回值是null
,因而会调用getDefaultJSExecutorFactory
方法创建默认的 js 执行器工厂实例。
接下来看看 ReactActivity
的实现。
ReactActivity
从上文可知,MainActivity
继承了 ReactActivity
,并重写了 getMainComponentName
方法。ReactActivity
是一个抽象类,其主要实现如下:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
// ...
public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
// 声明 ReactActivityDelegate 实例变量
private final ReactActivityDelegate mDelegate;
protected ReactActivity() {
// 在构造函数中创建 ReactActivityDelegate 实例
mDelegate = createReactActivityDelegate();
}
// 在子类 MainActivity 中重写了该方法,返回 js 端注册的 appKey
protected @Nullable String getMainComponentName() {
return null;
}
protected ReactActivityDelegate createReactActivityDelegate() {
// 创建 ReactActivityDelegate 实例
return new ReactActivityDelegate(this, getMainComponentName());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
//...
// 获取 ReactNativeHost 实例
protected final ReactNativeHost getReactNativeHost() {
return mDelegate.getReactNativeHost();
}
// 获取 ReactInstanceManager 实例
protected final ReactInstanceManager getReactInstanceManager() {
return mDelegate.getReactInstanceManager();
}
// 加载 RN App
protected final void loadApp(String appKey) {
mDelegate.loadApp(appKey);
}
}
ReactActivity
本身是一个抽象类,没有具体的功能实现,其主要作用有两个:
- 提供
getMainComponentName
方法的声明 - 创建
ReactActivityDelegate
实例,便于把具体的功能全委托给ReactActivityDelegate
类来处理
ReactActivityDelegate
ReactActivityDelegate
类的主要实现如下:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java
// ...
public class ReactActivityDelegate {
private final @Nullable Activity mActivity;
private final @Nullable String mMainComponentName;
// ...
private ReactDelegate mReactDelegate;
// 构造函数
public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
}
/**
* 获取 bundle 初始化的 props
* 如果需要初始化的 props,需要 Android 实现一个子类并重写这个方法或者自定义实现 ReactActivityDelegate
* 该方法的返回值会赋值给 js 端 run 方法的参数appParameters#initialProps
*/
protected @Nullable Bundle getLaunchOptions() {
return null;
}
// 获取 ReactRootView 实例
protected ReactRootView createRootView() {
return mReactDelegate.createRootView();
}
/**
* 获取当前应用使用的 ReactNativeHost 实例
* 上文有说到,在 ReactNativeHost 的实例是在 MainApplication 中创建的
*/
protected ReactNativeHost getReactNativeHost() {
return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
}
// 获取 ReactInstanceManager 实例
public ReactInstanceManager getReactInstanceManager() {
return mReactDelegate.getReactInstanceManager();
}
// 获取 appKey
public String getMainComponentName() {
return mMainComponentName;
}
protected void onCreate(Bundle savedInstanceState) {
String mainComponentName = getMainComponentName();
// 创建 ReactDelegate 实例
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions());
if (mMainComponentName != null) {
// 开启加载应用
loadApp(mainComponentName);
}
}
protected void loadApp(String appKey) {
// 实际是调用 ReactDelegate 实例的 loadApp 方法启动 RN 应用
mReactDelegate.loadApp(appKey);
// 调用Activity 的setContentView()方法,将根视图添加到当前的Activity
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}
// ...
protected Context getContext() {
return Assertions.assertNotNull(mActivity);
}
protected Activity getPlainActivity() {
return ((Activity) getContext());
}
}
ReactActivityDelegate
类主要是在其生命周期的 onCreate
方法中做了三件事:创建 ReactDelegate
实例、调用 ReactActivityDelegate#loadApp
开始启动 RN 应用以及设置当前 Activity 的根视图。
ReactDelegate
ReactDelegate
类的实现比较简单,关键部分代码如下:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java
// ...
public class ReactDelegate {
// ...
// 构造函数
public ReactDelegate(
Activity activity,
ReactNativeHost reactNativeHost,
@Nullable String appKey,
@Nullable Bundle launchOptions) {
mActivity = activity;
mMainComponentName = appKey;
mLaunchOptions = launchOptions;
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
mReactNativeHost = reactNativeHost;
}
// ...
public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
// 创建 RN 容器根视图
mReactRootView = createRootView();
mReactRootView.startReactApplication(
// 这里会去创建 ReactInstanceManager 实例
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}
public ReactRootView getReactRootView() {
return mReactRootView;
}
protected ReactRootView createRootView() {
return new ReactRootView(mActivity);
}
// ...
private ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
public ReactInstanceManager getReactInstanceManager() {
return getReactNativeHost().getReactInstanceManager();
}
}
ReactDelegate#loadApp
方法主要做了两件事:创建 RootView 和开始启动 React App。
ReactRootView
ReactRootView
是一个自定义的 View,其父类是 FrameLayout
,代码量比较大,因而我们只顺着上面的思路看一下 startReactApplication
的实现:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
// ...
public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
// ...
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties,
@Nullable String initialUITemplate) {
// ...
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 中
// 后文会再提到 mAttachedReactRoots
attachToReactInstanceManager();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
// ...
}
接下来我们看 ReactInstanceManager
对应代码的实现。
ReactInstanceManager
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
public void createReactContextInBackground() {
//略去日志输出代码
// 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)
public void recreateReactContextInBackground() {
// ...
recreateReactContextInBackgroundInner();
}
// ...
从代码中可以看到,createReactContextInBackground
在 Application 中只会被调用一次。当应用配置或者应用重新加载时,需要重新创建 ReactContext 信息,此时是去调用公开的 recreateReactContextInBackground
方法(注意:该方法有一个私有的实现,后续会提到)。但两个方法最终调用的实际都是 recreateReactContextInBackgroundInner
方法:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private void recreateReactContextInBackgroundInner() {
// ...
// 断言
UiThreadUtil.assertOnUiThread();
// 开发模式
if (mUseDeveloperSupport && mJSMainModulePath != null) {
final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
/**
* 省略代码
* 从上面条件的判断可以得知,这里主要是处理开发模式下,会从本地的服务器加载 bundle
*/
}
// 线上模式
recreateReactContextInBackgroundFromBundleLoader();
}
@ThreadConfined(UI)
private void recreateReactContextInBackgroundFromBundleLoader() {
// 省略输出日志的代码
// 调用私有实现
recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
}
// ...
@ThreadConfined(UI)
private void recreateReactContextInBackground(
JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
// ...
// 断言
UiThreadUtil.assertOnUiThread();
/**
* ReactContextInitParams 是一个私有类
* 主要是初始化类的 mJsExecutorFactory 和 mJsBundleLoader
* 后文会具体提到 ReactContextInitParams 类
*/
final ReactContextInitParams initParams =
new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
if (mCreateReactContextThread == null) {
// 开启新线程创建react context
runCreateReactContextOnNewThread(initParams);
} else {
//创建 ReactContext 的后台任务已经开启,缓存initParams在队列中等待重新创建 ReactContext
mPendingReactContextInitParams = initParams;
}
}
// ...
recreateReactContextInBackground
方法的私有实现中,有两个形参:jsExecutorFactory
和 jsBundleLoader
:
- jsExecutorFactory:js 执行器工厂实例,作为 C++ 和 js 双向通信的桥梁
- jsBundleLoader:加载器实例,用于加载 js bundle
接着往下看 runCreateReactContextOnNewThread
的实现:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
// ...
// 创建一个新线程
mCreateReactContextThread = new Thread (
null,
new Runnable () {
@Override
public void run () {
// ...
try {
// 设置当前线程的优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
// 创建 ReactContext
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
mCreateReactContextThread = null;
// ...
Runnable setupReactContextRunnable =
new Runnable() {
@Override
public void run() {
try {
// 后文会再提到这行代码
setupReactContext(reactApplicationContext);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
};
// 开启线程运行 setupReactContextRunnable
reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
} catch (Exception e) {
// ...
}
}
}
)
// 启动线程
mCreateReactContextThread.start();
}
// ...
runCreateReactContextOnNewThread
方法的核心是调用 createReactContext
方法来创建 React Context:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
// 略去日志输出代码
/**
* 传入 Android Application 的实例去创建 ReactContext 实例
* ReactApplicationContext 继承自 ReactContext,仅仅是简单包装了一下
* Android Application,全部的功能都在 ReactContext 类中实现
*/
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
// 设置 Native Module 调用的异常处理器
NativeModuleCallExceptionHandler exceptionHandler =
mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
/**
* 创建 Native Module 注册表,将Java可调用的API暴露给 js
* mPackages 在创建 ReactInstanceManager 实例时已被初始化
*/
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
// 先处理 jsExecutor/nativeModuleRegistry/jsBundleLoader 等参数,便于后续构建 CatalystInstance 实例
CatalystInstanceImpl.Builder catalystInstanceBuilder =
new CatalystInstanceImpl.Builder()
// 设置 React 队列配置(UI、js、native modules 三个线程队列)
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
// 略去日志输出代码
final CatalystInstance catalystInstance;
try {
// 创建 CatalystInstance 实例
catalystInstance = catalystInstanceBuilder.build();
} finally {
// 略去日志输出代码
}
// 初始化 ReactContext 的队列配置(UI、js、native modules 三个线程队列)
reactContext.initializeWithInstance(catalystInstance);
/**
* 初始化 JSI(JavaScript Interface)
* JSI & JSC 的讨论:https://github.com/react-native-community/discussions-and-proposals/issues/91
* 从上文可知,mJSIModulePackage 的值是 null
*/
if (mJSIModulePackage != null) {
catalystInstance.addJSIModules(
mJSIModulePackage.getJSIModules(
reactContext, catalystInstance.getJavaScriptContextHolder()));
//TurboModules : https://github.com/react-native-community/discussions-and-proposals/issues/40
if (ReactFeatureFlags.useTurboModules) {
catalystInstance.setTurboModuleManager(
catalystInstance.getJSIModule(JSIModuleType.TurboModuleManager));
}
}
// 略去日志输出代码
// 开始加载 js Bundle
catalystInstance.runJSBundle();
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
return reactContext;
}
// ...
createReactContext
方法主要作了如下四件事:
- 创建 NativeModule 注册表,并交由 CatalystInstance 管理
- 创建 CatalystInstance 实例
- 如果存在 JSI Module,就对其进行注册
- 关联 ReactContext 和 CatalystInstance,并开始加载 js bundle
CatalystInstance
是一个接口类型,定义了一系列 JSC(JavaScript Core) Bridge API 接口,提供了允许(从 Java 层)调用 JS 方法的环境,同时提供了部分 Java API 供 JS 层调用,其具体实现是 CatalystInstanceImpl
类。
下一篇我们继续接着分析 CatalystInstanceImpl
类。