1 简介
1.1 ReactNative的跨平台
ReactNative是一种跨平台开发App的技术,跨平台使得用一套代码就能在多个平台发布,节省了人力和各种资源。
怎么实现跨平台呢?回想两个我们已经掌握的知识你就能明白了。
1 回想一下当我们遇到大量重复性代码的时候会怎么做?是不是会考虑将有共性的东西抽象出来,同一个App虽然在Android和IOS的两个平台上代码实现上完全不同,但其实视图、交互以及业务逻辑这些都是具有共性的,是可以抽象出来的。
2 java也是跨平台的,我们回想一下java一次编译,到处运行的原理:先将java编译成字节码,然后在不同平台,jvm使用其内部相应的解释器解释成机器码(每个平台解释出来的机器码内容是不同的,看完下一段话后自己思考一下对应了什么!)。
因此我们可以这样实现跨平台:将视图、交互以及业务逻辑抽象出来,然后使用同一套代码(RN选择了Js)来实现,最后再使用不同的解释器,解释给各个平台。
1.2 简析RN工程的架构
本质上RN是一个第三方框架,它提供了执行js代码的能力,同时搭建了一套js和原生(Android和IOS)的通信体系。原生使用这个框架后,就可以将一部分功能的实现和逻辑的处理转移到js(本来实现这部分的功能和逻辑需要两套代码,即Android和IOS各自实现一遍,现在使用js一套代码就能实现)。由此可见尽可能的将更多的功能用js来实现就能节省更多的代码,但实际上js能力是十分有限的,比如js没有绘制引擎,因此我们用js写的UI本质上,最终是js告知原生UI的信息(位置,大小,颜色等),由原生负责真正的绘制。
可以看出js更多的是一种逻辑处理,而原生负责真正的实现,核型工作原理就是js和原生通过RN搭建的通讯体系进行协作和通讯。
具体native和js是怎么协作和通讯的呢?从使用的角度,我们只需要知道,js如何调用native和native如何调用js。要深入探究原理的话,由于两者的底层通讯是用c++实现的,就变成了js调用c++,c++调用原生,以及原生调用c++,c++调用js。由于我暂时不会c++,接下来的分析涉及到的RN源码只限于java和js。
2 RN的启动流程
RN项目是原生项目的扩展(我们的js代码被打包成一个bundle文件,作为资源文件放在原生项目中),本质上还是原生项目。因此我们从Android项目的角度入手,结合源码进行分析。
2.1 创建Application
Android项目启动的第一步当然是创建Application对象,来看看RN为我们提供的ReactApplication。
public interface ReactApplication {
ReactNativeHost getReactNativeHost();
}
ReactApplication是一个接口,提供一个返回ReactNativeHost对象的方法。
再来看看RN项目默认创建的Application。
public class MainApplication extends Application implements ReactApplication { // 实现ReactApplication接口
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {// 创建一个final的ReactNativeHost对象
@Override
// 配置是否是dev(开发)模式,是的话会开启一些调试,同时导致加载jsBundle的方式不一样。
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() { // 配置要加载的ReactPackage
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() { // 配置js的入口模块名
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {// 提供一个返回ReactNativeHost对象的方法
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
// SoLoader是so文件加载库,用来加载C/C++底层库
SoLoader.init(this, /* native exopackage */ false);
// 初始化Flipper。Flipper是facebook推出的用于 debug ios、Android、React Native 应用的工具。
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.awesomeproject.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
类似我们平时提供一个全局的ApplicaitionContext一样,这里提供了一个全局的ReactNativeHost对象。ReactNativeHost是一个抽象类,我们可以通过重写它的方法(getUseDeveloperSupport和getPackages没有默认实现,必须重写)来实现一些关于RN的全局配置。一个ReactPackage可以配置多个ViewManager、NativeModule,这部分是关于js调用原生的使用,详见ReactNative官方文档。
2.2 创建Activity
下一步就是创建MainActivity了,来看看RN项目默认创建的MainActivity。
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {// 返回js注册的主组件名。后续存到ReactRootView的mJSModuleName属性。
return "AwesomeProject";
}
}
继承了ReactActivity,重写了getMainComponentName方法。
Activity创建完就该走生命周期流程了,我们的onCreate方法呢?让我们进入ReactActivity一起看看。
2.2.1 ReactActivity
public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private final ReactActivityDelegate mDelegate;
// 初始化时创建ReactActivityDelegate代理对象
protected ReactActivity() {
mDelegate = createReactActivityDelegate();
}
protected @Nullable String getMainComponentName() {
return null;
}
// 创建ReactActivityDelegate时,为其绑定当前Activity和mainComponentName。
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
...
// 其他委派方法
}
ReactActivity初始化时创建ReactActivityDelegate代理对象,并将自己的生命周期、硬件返回按钮事件和权限相关的回调,全部委派给了ReactActivityDelegate对象。因此ReactActivity的onCreate方法就进入到了ReactActivityDelegate的onCreate方法。
2.2.2 ReactActivityDelegate
public class ReactActivityDelegate {
private final @Nullable Activity mActivity;
private final @Nullable String mMainComponentName;
private @Nullable PermissionListener mPermissionListener;
private @Nullable Callback mPermissionsCallback;
private ReactDelegate mReactDelegate;
@Deprecated
public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
}
// 初始化绑定了宿主ReactActivity和js主组件名
public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
}
protected @Nullable Bundle getLaunchOptions() {
return null;
}
protected ReactRootView createRootView() {// 默认创建ReactRootView的方法,可以重写此方法来自定义创建方法。
return new ReactRootView(getContext());
}
protected ReactNativeHost getReactNativeHost() {
return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
}
public ReactInstanceManager getReactInstanceManager() {
return mReactDelegate.getReactInstanceManager();
}
public String getMainComponentName() {
return mMainComponentName;
}
protected void onCreate(Bundle savedInstanceState) {
String mainComponentName = getMainComponentName();
// 创建ReactDelegate对象
mReactDelegate =
new ReactDelegate(
getPlainActivity(), // 宿主Activity
getReactNativeHost(), // 全局的ReactNativeHost对象
mainComponentName, // js入口组件
getLaunchOptions()) // Bundle对象,用来存放传递给js的初始化参数,默认为null
{
@Override
protected ReactRootView createRootView() { // 配置初始化ReactRootView的方法,
return ReactActivityDelegate.this.createRootView();
}
};
// 之前配置的mainComponentName不为空的话调用loadApp方法
if (mMainComponentName != null) {
loadApp(mainComponentName);// 传入mainComponentName
}
}
protected void loadApp(String appKey) {
// 加载js代码的入口
mReactDelegate.loadApp(appKey);
// 为宿主Activity绑定contentView(熟悉吗OvO)
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}
...
protected Context getContext() {
return Assertions.assertNotNull(mActivity);
}
protected Activity getPlainActivity() {
return ((Activity) getContext());
}
}
在onCreate方法中首先创建ReactDelegate对象,然后调用了ReactDelegate的loadApp方法,最后在调用setContentView方法传入了一个ReactRootView。**本质上比起普通的Activity,只是setContentView的内容不一样了。**前面说过js负责告诉原生视图长啥样,原生负责渲染,ReactRootView就是js给原生的答案,让我们看看ReactDelegate的loadApp方法。
2.2.3 ReactDelegate
public class ReactDelegate {
private final Activity mActivity;
private ReactRootView mReactRootView;
@Nullable private final String mMainComponentName;
@Nullable private Bundle mLaunchOptions;
@Nullable private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
private ReactNativeHost mReactNativeHost;
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() {
loadApp(mMainComponentName);
}
public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();// 创建一个ReactRootView对象
mReactRootView.startReactApplication( // 然后调用startReactApplication方法
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}
public ReactRootView getReactRootView() {
return mReactRootView;
}
// ReactActivityDelegate创建ReactDelegate时重写了此方法
protected ReactRootView createRootView() {
return new ReactRootView(mActivity);
}
...
private ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
public ReactInstanceManager getReactInstanceManager() {
return getReactNativeHost().getReactInstanceManager();
}
}
loadApp方法中首先创建一个ReactRootView对象,然后调用了ReactRootView对象的startReactApplication方法。
2.2.4 ReactRootView
ReactRootView的创建非常简单,我们的重点是startReactApplication方法:
public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
...
public ReactRootView(Context context) {
super(context);
init();
}
public ReactRootView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ReactRootView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
setClipChildren(false);
}
}
ReactRootView#startReactApplication:
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(), // 获取ReactInstanceManager对象
appKey, // mainComponentName
mLaunchOptions // 前面有提到,Bundle对象,存放传递给主组件的参数,默认为null
);
首先是调用ReactNativeHost对象的getReactInstanceManager()获取ReactInstanceManager对象。
2.2.5 ReactInstanceManager
ReactNativeHost.java
public abstract class ReactNativeHost {
private final Application mApplication;
// 全局唯一的ReactNativeHost管理了一个mReactInstanceManager对象,因此mReactInstanceManager也是全局单例。
private @Nullable ReactInstanceManager mReactInstanceManager;
protected ReactNativeHost(Application application) {
mApplication = application;
}
public ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceManager == null) { // 没有的话创建
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
// 调用createReactInstanceManager方法创建一个ReactInstanceManager对象
mReactInstanceManager = createReactInstanceManager();
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
}
return mReactInstanceManager;// 有的话直接返回
}
// 创建ReactInstanceManager对象的方法
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
ReactInstanceManagerBuilder builder =
ReactInstanceManager.builder()
.setApplication(mApplication)// 应用上下文
.setJSMainModulePath(getJSMainModuleName())// debug模式下jsBundle名
.setUseDeveloperSupport(getUseDeveloperSupport())// 是否开启dev模式
.setDevSupportManagerFactory(getDevSupportManagerFactory())
.setRequireActivity(getShouldRequireActivity())
.setSurfaceDelegateFactory(getSurfaceDelegateFactory())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setUIImplementationProvider(getUIImplementationProvider())
.setJSIModulesPackage(getJSIModulePackage())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
.setReactPackageTurboModuleManagerDelegateBuilder(
getReactPackageTurboModuleManagerDelegateBuilder());
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
// 配置jsBundle的加载路径(后续加载的时候用到)
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;
}
// dev模式下从服务器传过来的jsBundle的默认名
protected String getJSMainModuleName() {
return "index.android";
}
// 通过配置jsBundle在资源文件夹(assets文件夹)下的文件名来加载jsBundle
protected @Nullable String getBundleAssetName() {
return "index.android.bundle";
}
// 通过配置jsBundle的文件路径来加载jsBundle,默认为null
protected @Nullable String getJSBundleFile() {
return null;
}
public abstract boolean getUseDeveloperSupport(
protected abstract List<ReactPackage> getPackages();
...
// 其他默认配置,大部分都是null
}
ReactNativeHost将核心任务统统交给了ReactInstanceManager,初始化ReactInstanceManager时,也初始化了很多关于RN的默认配置,包括是否开启debug模式,后续加载jsBundle的方式,ReactPackage等等,我们可以重写初始化ReactNativeHost的方法来修改默认配置。当然真正的创建在ReactInstanceManagerBuilder的build方法中。
ReactInstanceManagerBuilder.java#build
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
//noinspection ConstantConditions
String appName = mApplication.getPackageName();
String deviceName = getFriendlyDeviceName();
return new ReactInstanceManager(
mApplication,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
? getDefaultJSExecutorFactory(appName, deviceName, mApplication.getApplicationContext())
: mJavaScriptExecutorFactory,
//创建JSBundleLoader对象来存储关于加载jsBundle的方式和路径,其内部后续再来看
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
mJSMainModulePath,
mPackages,
mUseDeveloperSupport,
mDevSupportManagerFactory == null
? new DefaultDevSupportManagerFactory()
: mDevSupportManagerFactory,
mRequireActivity,
mBridgeIdleDebugListener,
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
mUIImplementationProvider,
mNativeModuleCallExceptionHandler,
mRedBoxHandler,
mLazyViewManagersEnabled,
mDevBundleDownloadListener,
mMinNumShakes,
mMinTimeLeftInFrameForNonBatchedOperationMs,
mJSIModulesPackage,
mCustomPackagerCommandHandlers,
mTMMDelegateBuilder,
mSurfaceDelegateFactory
);
}
ReactInstanceManager中的一些配置,在后续使用到了再来分析,我们接着看startApplication方法。
ReactRootView.java#startApplication
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties) {
startReactApplication(reactInstanceManager, moduleName, initialProperties, null);
}
@ThreadConfined(UI)
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties,
@Nullable String initialUITemplate) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
try {
UiThreadUtil.assertOnUiThread();
//断言,确保mReactInstanceManager不为空
Assertions.assertCondition(
mReactInstanceManager == null,
"This root view has already been attached to a catalyst instance manager");
mReactInstanceManager = reactInstanceManager;
// 前面一路传进来的参数改个名而已
// js主组件名,ReactActivity的getJSMainModuleName,ReactActivityDelegate的mainComponentName。
mJSModuleName = moduleName;
// 传递给js主组件的初始化数据,默认为null,ReactActivityDelegate的mLaunchOptions
mAppProperties = initialProperties;
mInitialUITemplate = initialUITemplate;
// 创建ReactContext
mReactInstanceManager.createReactContextInBackground();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
核心是调用了mReactInstanceManager的createReactContextInBackground()方法来创建ReactContext,ReactContext和其他Context一样继承ContextWrapper,是ReactNative的上下文,我们通过ReactContext来访问RN的各种核心实现类。
2.3 创建ReactContext
ReactInstanceManager.java#createReactContextInBackground
@ThreadConfined(UI)
public void createReactContextInBackground() {
FLog.d(TAG, "ReactInstanceManager.createReactContextInBackground()");
UiThreadUtil.assertOnUiThread();
if (!mHasStartedCreatingInitialContext) {
mHasStartedCreatingInitialContext = true;
// 如果没有创建过ReactContext,就调用recreateReactContextInBackgroundInner方法创建
recreateReactContextInBackgroundInner();
}
}
//重新创建react的application和context,此方法用于配置发生变化或者我们主动要求重启RN应用时。
@ThreadConfined(UI)
public void recreateReactContextInBackground() {
Assertions.assertCondition(
mHasStartedCreatingInitialContext,
"recreateReactContextInBackground should only be called after the initial "
+ "createReactContextInBackground call.");
recreateReactContextInBackgroundInner();
}
@ThreadConfined(UI)
private void recreateReactContextInBackgroundInner() {
FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");
PrinterHolder.getPrinter()
.logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
UiThreadUtil.assertOnUiThread();
// 如果是dev环境且mJSMainModulePath不为空,则从metro服务器加载jsBundle
if (mUseDeveloperSupport && mJSMainModulePath != null) {
final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
if (mBundleLoader == null) {
// 从metro服务器加载jsBundle
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 (mDevSupportManager.hasUpToDateJSBundleInCache()
&& !devSettings.isRemoteJSDebugEnabled()
&& !mUseFallbackBundle) {
// 在禁用远程JS调试的情况下,使用服务器之前下载的最新的jsBundle
onJSBundleLoadedFromServer();
} else {
// 如果dev服务器关闭了,则关闭远程JS调试。
devSettings.setRemoteJSDebugEnabled(false);
recreateReactContextInBackgroundFromBundleLoader();
}
}
});
}
});
}
return;
}
}
// 非dev模式下调用
recreateReactContextInBackgroundFromBundleLoader();
}
@ThreadConfined(UI)
private void recreateReactContextInBackgroundFromBundleLoader() {
FLog.d(TAG, "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()");
PrinterHolder.getPrinter()
.logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader");
// mJavaScriptExecutorFactory默认为空,mBundleLoader保存了加载jsBundle的方式和路径,是前面创建ReactInstanceManager时,根据我们的配置创建的。
recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
}
@ThreadConfined(UI)
private void recreateReactContextInBackground(
JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
FLog.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackground()");
UiThreadUtil.assertOnUiThread();
final ReactContextInitParams initParams =
new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
if (mCreateReactContextThread == null) {
// 如果当前没有创建ReactContext的线程,则创建一个新线程来创建ReactCotext。
runCreateReactContextOnNewThread(initParams);
} else {
mPendingReactContextInitParams = initParams;
}
}
@ThreadConfined(UI)
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
...
mCreateReactContextThread =
new Thread(
null,
new Runnable() {
@Override
public void run() {
...
mHasStartedCreatingInitialContext = true;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
ReactMarker.logMarker(VM_INIT);
// 创建ReactContext的入口
// ReactApplicationContext继承ReactContext,简单的包装了一下
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
...
// 创建一个Runnable,封装了成功创建ReactContext后要做的事。
Runnable setupReactContextRunnable =
new Runnable() {
@Override
public void run() {
try {
setupReactContext(reactApplicationContext);
} catch (Exception e) {
// TODO T62192299: remove this after investigation
FLog.e(
ReactConstants.TAG,
"ReactInstanceManager caught exception in setupReactContext",
e);
mDevSupportManager.handleException(e);
}
}
};
// 在NativeModule线程中,执行setupReactContextRunnable
reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
},
"create_react_context");
mCreateReactContextThread.start();
}
可以看到最终是调用了createReactContext方法,然后创建一个Runnable,封装了成功创建ReactContext后要做的事。我们来看看创建ReactContext的核心方法。
ReactInstanceManager.java#createReactContext
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
...
// 创建ReactApplicationContext对象
ReactApplicationContext reactContext = new ReactApplicationContext(this.mApplicationContext);
// mPackages就是我们之前在ReactNativeHost配置的ReactPackage列表
// processPackages方法将ReactPackage列表封装成NativeModule注册表(NativeModuleRegistry对象)
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
//创建CatalystInstanceImpl.Builder对象
CatalystInstanceImpl.Builder catalystInstanceBuilder =
new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)// 设置NativeModule注册表
.setJSBundleLoader(jsBundleLoader)// 设置jsBundleLoader
.setNativeModuleCallExceptionHandler(exceptionHandler);
...
final CatalystInstance catalystInstance;
try {
//创建CatalystInstanceImpl对象
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
// 将CatalystInstanceImpl对象绑定到reactContext上
reactContext.initializeWithInstance(catalystInstance);
if (mJSIModulePackage != null) {
catalystInstance.addJSIModules(
mJSIModulePackage.getJSIModules(
reactContext, catalystInstance.getJavaScriptContextHolder()));
}
...
// 加载jsBundle
catalystInstance.runJSBundle();
return reactContext;
}
首先创建了ReactContext对象,然后创建了CatalystInstanceImpl对象并绑定到ReactContext,然后调用CatalystInstanceImpl对象的runJSBundle方法来加载jsBundle。等会再说什么是加载jsBundle,先来看看CatalystInstanceImpl对象。
2.3.1 CatalystInstanceImpl的初始化
CatalystInstanceImpl可以说承载了ReactContext的核心功能,它的初始化十分重要,我们来看看CatalystInstanceImpl在初始化做了什么。
public class CatalystInstanceImpl implements CatalystInstance {
static {
// 加载so库中的reactnativejni库
ReactBridge.staticInit();
}
private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
// Access from any thread
private final ReactQueueConfigurationImpl mReactQueueConfiguration;
private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
private final String mJsPendingCallsTitleForTrace =
"pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
private volatile boolean mDestroyed = false;
private final TraceListener mTraceListener;
private final JavaScriptModuleRegistry mJSModuleRegistry;
private final JSBundleLoader mJSBundleLoader;
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
private final Object mJSCallsPendingInitLock = new Object();
private final NativeModuleRegistry mNativeModuleRegistry;
private final JSIModuleRegistry mJSIModuleRegistry = new JSIModuleRegistry();
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
private final MessageQueueThread mNativeModulesQueueThread;
private boolean mInitialized = false;
private volatile boolean mAcceptCalls = false;
private boolean mJSBundleHasLoaded;
private @Nullable String mSourceURL;
private JavaScriptContextHolder mJavaScriptContextHolder;
private volatile @Nullable TurboModuleRegistry mTurboModuleRegistry = null;
private @Nullable JSIModule mTurboModuleManagerJSIModule = null;
// C++ parts,native方法
private final HybridData mHybridData;
private static native HybridData initHybrid(
boolean enableRuntimeScheduler, boolean enableRuntimeSchedulerInTurboModule);
public native CallInvokerHolderImpl getJSCallInvokerHolder();
public native CallInvokerHolderImpl getNativeCallInvokerHolder();
// 构造函数
private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
...
mReactQueueConfiguration =
// 调用ReactQueueConfigurationImpl的静态方法,来创建整个通信体系要用到的线程
ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec, new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry; // nativeModule注册表
mJSModuleRegistry = new JavaScriptModuleRegistry();// JavaScriptModule注册表
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
...
// native方法,初始化c++通信桥
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),// nativeModules中Js调用java的部分
mNativeModuleRegistry.getCxxModules());// nativeModules中Js调用c++的部分
...
}
}
CatalystInstanceImpl在主要做了两件事创建通信体系要用到的线程,创建通信体系底层要用到的c++桥。
2.3.1.1 创建js线程和nativeModules线程
ReactQueueConfigurationImpl.java#create
public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
private final MessageQueueThreadImpl mUIQueueThread;
private final MessageQueueThreadImpl mNativeModulesQueueThread;
private final MessageQueueThreadImpl mJSQueueThread;
...
public static ReactQueueConfigurationImpl create(
ReactQueueConfigurationSpec spec, QueueThreadExceptionHandler exceptionHandler) {
// 创建一个HashMap
Map<MessageQueueThreadSpec, MessageQueueThreadImpl> specsToThreads = MapBuilder.newHashMap();
// UI线程:主线程
MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
MessageQueueThreadImpl uiThread = MessageQueueThreadImpl.create(uiThreadSpec, exceptionHandler);
specsToThreads.put(uiThreadSpec, uiThread);
// js线程:负责执行js代码
MessageQueueThreadImpl jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
if (jsThread == null) {
jsThread = MessageQueueThreadImpl.create(spec.getJSQueueThreadSpec(), exceptionHandler);
}
// nativeModules线程:处理nativeModules相关内容
MessageQueueThreadImpl nativeModulesThread =
specsToThreads.get(spec.getNativeModulesQueueThreadSpec());
if (nativeModulesThread == null) {
nativeModulesThread =
MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
}
return new ReactQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
}
}
用一个HashMap存MessageQueueThreadImpl对象,MessageQueueThreadImpl对象保存了线程相关的信息。
MessageQueueThreadImpl.java#create
public static MessageQueueThreadImpl create(
MessageQueueThreadSpec spec, QueueThreadExceptionHandler exceptionHandler) {
switch (spec.getThreadType()) {
case MAIN_UI:
// 直接使用mainLooper创建MessageQueueThreadImpl对象
return createForMainThread(spec.getName(), exceptionHandler);
case NEW_BACKGROUND:
// 手动创建Looper和线程,然后创建MessageQueueThreadImpl对象。
return startNewBackgroundThread(spec.getName(), spec.getStackSize(), exceptionHandler);
default:
throw new RuntimeException("Unknown thread type: " + spec.getThreadType());
}
}
MessageQueueThreadImpl.java#createForMainThread
/** @return a MessageQueueThreadImpl corresponding to Android's main UI thread. */
private static MessageQueueThreadImpl createForMainThread(
String name, QueueThreadExceptionHandler exceptionHandler) {
Looper mainLooper = Looper.getMainLooper();
final MessageQueueThreadImpl mqt =
new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
...
return mqt;
}
MessageQueueThreadImpl.java#startNewBackgroundThread
private static MessageQueueThreadImpl startNewBackgroundThread(
final String name, long stackSize, QueueThreadExceptionHandler exceptionHandler) {
...
Thread bgThread =
new Thread(
null,
new Runnable() {
@Override
public void run() {
...
Looper.prepare();
...
Looper.loop();
}
},
"mqt_" + name,
stackSize);
bgThread.start();
return new MessageQueueThreadImpl(name, pair.first, exceptionHandler, pair.second);
}
2.3.1.2 初始化c++桥
- NativeModuleRegistry是在createReactContext()方法创建并添加module的。
- JavaScriptModuleRegistry是在CatalystInstanceImpl的构建方法创建并添加module的。
在ReactInstanceManager的构造函数中,有这样一段代码添加了核心的JavaScriptModule
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();
}
},
mUIImplementationProvider,
lazyViewManagersEnabled,
minTimeLeftInFrameForNonBatchedOperationMs));
if (mUseDeveloperSupport) {
mPackages.add(new DebugCorePackage());
}
mPackages.addAll(packages);
}
initializeBridge方法会通过jni调用native方法完成c++侧的CatalystInstance的初始化。
private native void initializeBridge(
ReactCallback callback, // 回调方法,CatalystInstanceImpl的静态内部类ReactCallbac
JavaScriptExecutor jsExecutor, // 默认为空
MessageQueueThread jsQueue, // JS线程
MessageQueueThread moduleQueue, // nativeModules线程
Collection<JavaModuleWrapper> javaModules, // nativeModules中Js调用java的部分
Collection<ModuleHolder> cxxModules// nativeModules中Js调用c++的部分
);
javaModules和cxxModules会在CatalystInstanceImpl.cpp的initializeBridge方法中被打包成ModuleRegistry传入Instance.cpp中。
ModuleRegistry再通过Instance的initializeBridge方法传到NativeToJsBridge.cpp中的构造函数中然后传到JsToNativeBridge。
-
NativeToJsBridge:NativeToJsBridge是java调用js的桥梁,用来调用jsModule。
-
JsToNativeBridge:JsToNativeBridge是js调用java的桥梁,用来调用nativeModule。
2.3.2 加载jsBundle
加载Js代码本质上就是将jsBundle这个资源文件加载到内存中,加载完就意味着我们开始执行js代码,调用index.js里面的AppRegistry.registerComponent方法来完成组件的注册,但此时渲染还未开始。
AppRegistry.js#registerComponent
registerComponent(
appKey: string, // 组件名
componentProvider: ComponentProvider, // 一个返回组件的函数
section?: boolean,
): string {
let scopedPerformanceLogger = createPerformanceLogger();
// runnables是一个存放键值对的对象,可以理解成map。
runnables[appKey] = {
componentProvider,
run: (appParameters, displayMode) => {
renderApplication( // 渲染入口方法,此时还未被调用。等run方法被调用时才开始渲染。
componentProviderInstrumentationHook(
componentProvider,
scopedPerformanceLogger,
),
appParameters.initialProps,
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
appParameters.fabric,
showArchitectureIndicator,
scopedPerformanceLogger,
appKey === 'LogBox',
appKey,
coerceDisplayMode(displayMode),
appParameters.concurrentRoot,
);
},
};
if (section) {
sections[appKey] = runnables[appKey];
}
return appKey;
},
CatalystInstanceImpl是怎么加载jsBundle的呢?
CatalystInstanceImpl.java#runJSBundle
public void runJSBundle() {
...
// 传入CatalystInstanceImpl对象
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
...
}
内部直接调用mJSBundleLoader的loadScript,mJSBundleLoade就是在前面的ReactInstanceManagerBuilder.java#build
中调用JSBundleLoader.createAssetLoader创建的。
JSBundleLoader.java#createAssetLoader
public abstract class JSBundleLoader {
public static JSBundleLoader createAssetLoader(
final Context context, final String assetUrl, final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
}
...
}
总共有三种加载jsBundle的方式:
- setSourceURLs(String deviceURL, String remoteURL) :从远程服务器加载
- loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously):从Assets文件夹加载
- loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously):从文件路径加载
观察创建ReactInstanceManager的部分就会知道,dev模式下会从远程服务下载,默认是使用第二种加载Assets文件夹下的"index.android.bundle"文件,如果同时配置了第二和第三种,第三种优先级更高。
loadScript方法的参数是JSBundleLoaderDelegate对象,而前面传入了CatalystInstanceImpl对象,不出意外CatalystInstanceImpl就是
JSBundleLoaderDelegate对象。
public class CatalystInstanceImpl implements CatalystInstance {}
public interface CatalystInstance extends MemoryPressureListener, JSInstance, JSBundleLoaderDelegate {}
是了是了,也就是说加载jsBundle最终调用了CatalystInstanceImpl的loadScriptFromAssets方法。
CatalystInstanceImpl.java#loadScriptFromAssets
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
@Override
public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
}
最终加载jsBundle是通过jni的方式,调用了native方法jniLoadScriptFromAssets。(这里的native指的是c/c++)
在c++层完成加载jsBundle后,会进入MessageQueue.js开始执行js代码。
2.4 setupReactContext
前面说到创建万ReactContext后还要调用setupReactContext方法
ReactInstanceManager.java#setupReactContext
private void setupReactContext(final ReactApplicationContext reactContext) {
...
synchronized (mAttachedReactRoots) {
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
catalystInstance.initialize();
...
for (ReactRoot reactRoot : mAttachedReactRoots) {
if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) {
// 将ReactRoot绑定到ReactInstanceManager
attachRootViewToInstance(reactRoot);
}
}
}
...
}
ReactInstanceManager.java#attachRootViewToInstance
private void attachRootViewToInstance(final ReactRoot reactRoot) {
@Nullable
UIManager uiManager =
UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());
...
// ReactRootView.startApplication传的mLaunchOptions
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
final int rootTag;
if (reactRoot.getUIManagerType() == FABRIC) {
rootTag =
uiManager.startSurface(
reactRoot.getRootViewGroup(),
reactRoot.getJSModuleName(),
initialProperties == null
? new WritableNativeMap()
: Arguments.fromBundle(initialProperties),
reactRoot.getWidthMeasureSpec(),
reactRoot.getHeightMeasureSpec());
reactRoot.setRootViewTag(rootTag);
reactRoot.setShouldLogContentAppeared(true);
} else {
// 将ReactRootView添加到UIManager上,会返回一个int型的rootTag来标识ReactRootView
rootTag =
uiManager.addRootView(
reactRoot.getRootViewGroup(),
initialProperties == null
? new WritableNativeMap()
: Arguments.fromBundle(initialProperties),
reactRoot.getInitialUITemplate());
reactRoot.setRootViewTag(rootTag);
// 启动ReactRootView
reactRoot.runApplication();
}
...
}
ReactRootView.java#runApplication
public void runApplication() {
try {
if (mReactInstanceManager == null || !mIsAttachedToInstance) {
return;
}
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
return;
}
CatalystInstance catalystInstance = reactContext.getCatalystInstance();
// 获取主组件名
String jsAppModuleName = getJSModuleName();
if (mWasMeasured) {
updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec);
}
WritableNativeMap appParams = new WritableNativeMap();
// 打包rootTag和appProperties到appParams
appParams.putDouble("rootTag", getRootViewTag());
@Nullable Bundle appProperties = getAppProperties();
if (appProperties != null) {
appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
}
mShouldLogContentAppeared = true;
// 调用AppRegistry这个JavaScriptModule的runApplication方法,传入主组件名和参数
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
至此就到达了进入js世界的入口,也就是调用了js代码的AppRegistry.runApplication方法。正式开始渲染rn组件。
AppRegistry.js#runApplication
runApplication(
appKey: string,
appParameters: any,
displayMode?: number,
): void {
...
runnables[appKey].run(appParameters, displayMode);// 取出之前注册的对象,执行run方法
},
来看前面注册时,run方法内部的renderApplication方法:
renderApplication.js#renderApplication
function renderApplication<Props: Object>(
RootComponent: React.ComponentType<Props>,
initialProps: Props,
rootTag: any,
WrapperComponent?: ?React.ComponentType<any>,
fabric?: boolean,
showArchitectureIndicator?: boolean,
scopedPerformanceLogger?: IPerformanceLogger,
isLogBox?: boolean,
debugName?: string,
displayMode?: ?DisplayModeType,
useConcurrentRoot?: boolean,
) {
...
let renderable = (
<PerformanceLoggerContext.Provider value={performanceLogger}>
<AppContainer
rootTag={rootTag}
fabric={fabric}
showArchitectureIndicator={showArchitectureIndicator}
WrapperComponent={WrapperComponent}
initialProps={initialProps ?? Object.freeze({})}
internal_excludeLogBox={isLogBox}>
<RootComponent {...initialProps} rootTag={rootTag} /> // 这里的RootComponent就是前面注册的组件,这里将原生传过来的initialProps和rootTag作为属性传给RootComponent
</AppContainer>
</PerformanceLoggerContext.Provider>
);
...
if (fabric) {
require('../Renderer/shims/ReactFabric').render(
renderable,
rootTag,
null,
useConcurrentRoot,
);
} else {
require('../Renderer/shims/ReactNative').render(renderable, rootTag);
}
...
}
至此组件开始渲染,先写到这。水平有限,对源码的阅读可能会出错,请多多理解。