ReactNative源码篇:启动流程

前端之家收集整理的这篇文章主要介绍了ReactNative源码篇:启动流程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

ReactNative源码篇:启动流程

作者: 郭孝星
邮箱: guoxiaoxingse@163.com
博客: http://blog.csdn.net/allenwells
简书: http://www.jianshu.com/users/66a47e04215b/latest_articles

关于作者

郭孝星,非著名程序员,代码洁癖患者,爱编程,好吉他,喜烹饪,爱一切有趣的事物和人。

关于文章

作者的文章会同时发布在Github、CSDN与简书上,文章顶部也会附上文章的Github链接。如果文章中有什么疑问也欢迎发邮件与我交流,对于交流
的问题,请描述清楚问题并附上代码与日志,一般都会给予回复。如果文章中有什么错误,也欢迎斧正。如果你觉得本文章对你有所帮助,也欢迎去
star文章,关注文章的最新的动态。另外建议大家去Github上浏览文章,一方面文章的写作都是在Github上进行的,所以Github上的更新是最及时
的,另一方面感觉Github对Markdown的支持更好,文章的渲染也更加美观。

文章目录:https://github.com/guoxiaoxing/react-native-android-container/blob/master/README.md

本篇系列文章主要分析ReactNative源码,分析ReactNative的启动流程、渲染原理、通信机制与线程模型等方面内容

在分析具体的启动流程之前,我们先从Demo代码入手,对外部的代码有个大致的印象,我们才能进一步去了解内部的逻辑。

1 首先我们会在应用的Application里做RN的初始化操作。

  1. //ReactNativeHost:持有ReactInstanceManager实例,做一些初始化操作。
  2. private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
  3. @Override
  4. public boolean getUseDeveloperSupport() {
  5. return BuildConfig.DEBUG;
  6. }
  7.  
  8. @Override
  9. protected List<ReactPackage> getPackages() {
  10. return Arrays.<ReactPackage>asList(
  11. new MainReactPackage()
  12. );
  13. }
  14. };
  15.  
  16. @Override
  17. public ReactNativeHost getReactNativeHost() {
  18. return mReactNativeHost;
  19. }
  20.  
  21. @Override
  22. public void onCreate() {
  23. super.onCreate();
  24. //SoLoader:加载C++底层库,准备解析JS。
  25. SoLoader.init(this,/* native exopackage */ false);
  26. }
  27. }

2 页面继承ReactActivity,ReactActivity作为JS页面的容器。

  1. public class MainActivity extends ReactActivity {
  2.  
  3. /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */
  4. @Override
  5. protected String getMainComponentName() {
  6. //返回组件名
  7. return "standard_project";
  8. }
  9. }

3 有了ReactActivity作为容器,我们就可以用JS开发页面了。

  1. import React,{ Component } from 'react';
  2. import {
  3. AppRegistry,StyleSheet,Text,View
  4. } from 'react-native';
  5.  
  6. //Component用来做UI渲染,生命周期控制,事件分发与回调。
  7. export default class standard_project extends Component {
  8. //render函数返回UI的界面结构(JSX编写,编译完成后最终会变成JS代码
  9. render() {
  10. return (
  11. <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started,edit index.android.js </Text> <Text style={styles.instructions}> Double tap R on your keyboard to reload,{'\n'} Shake or press menu button for dev menu </Text> </View> ); } } //创建CSS样式 const styles = StyleSheet.create({ container: { flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF',},welcome: { fontSize: 20,textAlign: 'center',margin: 10,instructions: { textAlign: 'center',color: '#333333',marginBottom: 5,}); //注册组件名,JS与Java格子各自维护了一个注册表 AppRegistry.registerComponent('standard_project',() => standard_project);

以上便是RN开发的三个步骤,本篇文章我们重点关注RN应用的启动流程,具体说来,有以下几个方面:

  1. 1 RN应用的启动的函数调用链,分析流程细节。
  2. 2 RN应用启动过程中创建了哪些组件,这些组件各自都由什么功能

在正式分析启动流程之前,我们先来了解和启动流程相关的一些重要概念。

ReactContext

整个启动流程重要创建实例之一就是ReactContext,在正式介绍启动流程之前,我们先来了接一下ReactContext的概念。

ReactContext继承于ContextWrapper,也就是说它和Android中的Context是一个概念,是整个应用的上下文。那么什么是上下文呢,我们知道Android的应用模型是基于组件的应用设计模式,
组件的运行需要完整的运行环境,这种运行环境便是应用的上下文。

上面的概念可能有点抽象,我们举个例子说明一下。

用户与操作系统的每一次交互都是一个场景,例如:打电话、发短信等有节目的场景(Activity),后台播放音乐等没有节目的场景(Service),这种交互的场景(Activity、Service等)都被
抽象成了上下文环境(Context),它代表了当前对象再应用中所处的一个环境、一个与系统交互的过程。

我们来了解一下ReactContext的具体实现与功能,先来看一下它的类图:

从上图可以看出,ReactContext继承与ContextWrapper,并有子类:

  1. ReactApplicationContext:继承于ReactContextReactContextwrapper类,就像ContextContextWrapper的关系一样。
  2. ThemedReactContext:继承于ReactContext,也是ReactContextwrapper类。

NativeModule/UIManagerModule/JavascriptModule

Module即模块,是暴露给对方调用的API集合。

NativeModule/UIManagerModule

  1. NativeModule/UIManagerModuleNativeModuleJava暴露给JS调用APU集合,例如:ToastModuleDialogModule等,UIManagerModule也是供JS调用API集合,它用来创建View
  2. 业务放可以通过实现NativeModule自定义模块,通过getName()将模块名暴露给JS层,通过@ReactMethod注解将API暴露给JS层。
  3.  
  4. JavaScriptModuleJS暴露给Java调用API集合,例如:AppRegistryDeviceEventEmitter等。业务放可以通过继承JavaScriptModule接口类似自定义接口模块,声明与JS相对应的方法
  5. 即可。

一 执行器的实现

在C++层的Executor.h文件中同一定义了执行Native代码的抽象类ExecutorDelegate,以及执行JS代码的抽象类JSExecutor。

1.1 Native代码执行器

ExecutorDelegate:在Executor.h中定义,由JsToNativeBridge实现,该抽象类用于JS代码调用Native代码,该类的类图如下所示:

  1. // This interface describes the delegate interface required by
  2. // Executor implementations to call from JS into native code.
  3. class ExecutorDelegate {
  4. public:
  5. virtual ~ExecutorDelegate() {}
  6.  
  7. //注册JS执行器
  8. virtual void registerExecutor(std::unique_ptr<JSExecutor> executor,std::shared_ptr<MessageQueueThread> queue) = 0;
  9. //注销JS执行器
  10. virtual std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) = 0;
  11.  
  12. //获取模块注册
  13. virtual std::shared_ptr<ModuleRegistry> getModuleRegistry() = 0;
  14.  
  15. //调用Native Module,在它实现中,它会进一步调用ModuleRegistry::callNativeMethod() -> NativeModule::invoke(),进而
  16. //完成对Native Module的调用
  17. virtual void callNativeModules(
  18. JSExecutor& executor,folly::dynamic&& calls,bool isEndOfBatch) = 0;
  19. virtual MethodCallResult callSerializableNativeHook(
  20. JSExecutor& executor,unsigned int moduleId,unsigned int methodId,folly::dynamic&& args) = 0;
  21. };

1.2 JS代码执行器

JS的解析是在Webkit-JavaScriptCore中完成的,JSCExexutor.cpp对JavaScriptCore的功能做了进一步的封装,我们来看一下它的实现。

JSExecutor:在Executor.h中定义,正如它的名字那样,它是用来执行JS代码的。执行代码的命令是通过JS层的BatchedBridge传递过来的。

我们先来看一下JSExecutor的类图,可以看到

  1. class JSExecutor {
  2. public:
  3. /** * Execute an application script bundle in the JS context. */
  4. virtual void loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) = 0;
  5.  
  6. /** * Add an application "unbundle" file */
  7. virtual void setJSModulesUnbundle(std::unique_ptr<JSModulesUnbundle> bundle) = 0;
  8.  
  9. /** * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID,* method ID and optional additional arguments in JS. The executor is responsible * for using Bridge->callNativeModules to invoke any necessary native modules methods. */
  10. virtual void callFunction(const std::string& moduleId,const std::string& methodId,const folly::dynamic& arguments) = 0;
  11.  
  12. /** * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,* and optional additional arguments in JS and returns the next queue. The executor * is responsible for using Bridge->callNativeModules to invoke any necessary * native modules methods. */
  13. virtual void invokeCallback(const double callbackId,const folly::dynamic& arguments) = 0;
  14.  
  15. virtual void setGlobalVariable(std::string propName,std::unique_ptr<const JSBigString> jsonValue) = 0;
  16. virtual void* getJavaScriptContext() {
  17. return nullptr;
  18. }
  19. virtual bool supportsProfiling() {
  20. return false;
  21. }
  22. virtual void startProfiler(const std::string &titleString) {}
  23. virtual void stopProfiler(const std::string &titleString,const std::string &filename) {}
  24. virtual void handleMemoryPressureUiHidden() {}
  25. virtual void handleMemoryPressureModerate() {}
  26. virtual void handleMemoryPressureCritical() {
  27. handleMemoryPressureModerate();
  28. }
  29. virtual void destroy() {}
  30. virtual ~JSExecutor() {}
  31. };

可以看到除了JSExecutor.cpp实现了抽象类JSExecutor里的方法,ProxyExecutor.cpp也实现了它里面的方法,这是RN给了我们自定义JS解析器的能力,可以在CatalystInstance.Builder里
setJSExecutor(),具体可以参见JavaJSExecutor与ProxyJavaScriptExecutor,它们的类图如下所示:

二 RN应用的启动流程

一句话概括启动流程:先是应用终端启动并创建应用上下文,应用上下文启动JS Runtime,进行布局,再由应用终端进行渲染,最后将渲染的View添加到ReactRootView上,最终呈现在用户面前。

RN应用的启动流程图如下所示:

详细流程:

  1. 1 在程序启动的时候,也就是ReContextactActivityonCreate()函数中,我们会去创建一个ReactInstanceManagerImpl对象
  2.  
  3. 2 ReactRootView作为整个RN应用的根视图,通过调用ReactRootView.startReactApplication()方法启动RN应用。
  4.  
  5. 3 RN应用页面渲染前,需要先创建ReactContext的创建流程在,异步任务ReactContextInitAsyncTask负责来完成这个任务。
  6.  
  7. 4 ReactContextInitAsyncTask后台ReactContextInitAsyncTask.doInBackground()执行ReactContext的创建,创建ReactContext的过程中,会依据ReactPackage创建JavaScriptModuleRegistry
  8. NativeModuleRegistry注册表以及它们的管理类CatalystInstanceImpl,同时创建JSNativeUI线程队列,并最终调用CatalystInstanceImpl.runJSBundle()去异步
  9. 加载JS Bundle文件
  10.  
  11. 5 后台任务执行完成后,在ReactContextInitAsyncTask.onPostExecute()会调用ReactInstanceManager.setupReactContext()设置创建好的ReactContext,并将
  12. ReactRootView加载进来,并调用RN应用的JS入口APPRegistry来启动应用。
  13.  
  14. 6 JS层找到已经注册的对应的启动组件,执行renderApplication()来渲染整个应用。

好,我们先从ReactActivity入手。

ReactActivity继承于Activity,并实现了它的生命周期方法。ReactActivity自己并没有做什么事情,所有的功能都由它的委托类ReactActivityDelegate来完成。

如下所示:

所以我们主要来关注ReactActivityDelegate的实现。我们先来看看ReactActivityDelegate的onCreate()方法

2.1 ReactActivityDelegate.onCreate(Bundle savedInstanceState)

  1. public class ReactActivityDelegate {
  2.  
  3. protected void onCreate(Bundle savedInstanceState) {
  4. boolean needsOverlayPermission = false;
  5. //开发模式判断以及权限检查
  6. if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  7. // Get permission to show redBox in dev builds.
  8. if (!Settings.canDrawOverlays(getContext())) {
  9. needsOverlayPermission = true;
  10. Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getContext().getPackageName()));
  11. FLog.w(ReactConstants.TAG,REDBox_PERMISSION_MESSAGE);
  12. Toast.makeText(getContext(),REDBox_PERMISSION_MESSAGE,Toast.LENGTH_LONG).show();
  13. ((Activity) getContext()).startActivityForResult(serviceIntent,REQUEST_OVERLAY_PERMISSION_CODE);
  14. }
  15. }
  16.  
  17. //mMainComponentName就是上面ReactActivity.getMainComponentName()返回的组件名
  18. if (mMainComponentName != null && !needsOverlayPermission) {
  19. //载入app页面
  20. loadApp(mMainComponentName);
  21. }
  22. mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  23. }
  24.  
  25. protected void loadApp(String appKey) {
  26. if (mReactRootView != null) {
  27. throw new IllegalStateException("Cannot loadApp while app is already running.");
  28. }
  29. //创建ReactRootView作为根视图,它本质上是一个FrameLayout
  30. mReactRootView = createRootView();
  31. //启动RN应用
  32. mReactRootView.startReactApplication(
  33. getReactNativeHost().getReactInstanceManager(),appKey,getLaunchOptions());
  34. //Activity的setContentView()方法
  35. getPlainActivity().setContentView(mReactRootView);
  36. }
  37. }

可以发现ReactActivityDelegate在创建时主要做了以下事情:

  1. 1 创建ReactRootView作为应用的容器,它本质上是一个FrameLayout
  2. 2 调用ReactRootView.startReactApplication()进一步执行应用启动流程。
  3. 3 调用Activity.setContentView()将创建的ReactRootView作为ReactActivitycontent view

尅看出RN真正核心的地方就在于ReactRootView,它就是一个View,你可以像用其他UI组件那样把它用在Android应用的任何地方。好,我们进一步去ReactRootView看启动流程。

2.2 ReactRootView.startReactApplication( ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle launchOptions)

  1. public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
  2.  
  3. /** * Schedule rendering of the react component rendered by the JS application from the given JS * module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the * JS context of that manager. Extra parameter {@param launchOptions} can be used to pass initial * properties for the react component. */
  4. public void startReactApplication(
  5. ReactInstanceManager reactInstanceManager,@Nullable Bundle launchOptions) {
  6. UiThreadUtil.assertOnUiThread();
  7.  
  8. // TODO(6788889): Use POJO instead of bundle here,apparently we can't just use WritableMap
  9. // here as it may be deallocated in native after passing via JNI bridge,but we want to reuse
  10. // it in the case of re-creating the catalyst instance
  11. Assertions.assertCondition(
  12. mReactInstanceManager == null,"This root view has already been attached to a catalyst instance manager");
  13.  
  14. mReactInstanceManager = reactInstanceManager;
  15. mJSModuleName = moduleName;
  16. mLaunchOptions = launchOptions;
  17.  
  18. //创建RN应用上下文
  19. if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
  20. mReactInstanceManager.createReactContextInBackground();
  21. }
  22.  
  23. // We need to wait for the initial onMeasure,if this view has not yet been measured,we set which
  24. // will make this view startReactApplication itself to instance manager once onMeasure is called.
  25. if (mWasMeasured) {
  26. attachToReactInstanceManager();
  27. }
  28. }
  29.  
  30. }

我们来看看这个函数的3个参数:

···
ReactInstanceManager reactInstanceManager:管理React实例。
String moduleName:模块的名字,对应ReactActivity.getMainComponentName()与AppRegistry.registerComponent()。
Bundle launchOptions:Bundle类型的数据,如果我们不继承ReactActivity而是自己实现页面容器,可以通过这个参数在startActivity()时传递参数到JS层。
···

我们可以看到,ReactRootView.startReactApplication()方法里最终会调用ReactInstanceManager.createReactContextInBackground()来创建RN应用的上下文。

2.3 ReactInstanceManager.createReactContextInBackground()

  1. public class ReactInstanceManager {
  2.  
  3. /** * Trigger react context initialization asynchronously in a background async task. This enables * applications to pre-load the application JS,and execute global code before * {@link ReactRootView} is available and measured. This should only be called the first time the * application is set up,which is enforced to keep developers from accidentally creating their * application multiple times without realizing it. * * Called from UI thread. */
  4. public void createReactContextInBackground() {
  5. Assertions.assertCondition(
  6. !mHasStartedCreatingInitialContext,"createReactContextInBackground should only be called when creating the react " +
  7. "application for the first time. When reloading JS,e.g. from a new file,explicitly" +
  8. "use recreateReactContextInBackground");
  9.  
  10. mHasStartedCreatingInitialContext = true;
  11. //进一步调用recreateReactContextInBackgroundInner()
  12. recreateReactContextInBackgroundInner();
  13. }
  14.  
  15. /** * 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. * * Called from UI thread. */
  16. public void recreateReactContextInBackground() {
  17. Assertions.assertCondition(
  18. mHasStartedCreatingInitialContext,"recreateReactContextInBackground should only be called after the initial " +
  19. "createReactContextInBackground call.");
  20. recreateReactContextInBackgroundInner();
  21. }
  22.  
  23. private void recreateReactContextInBackgroundInner() {
  24. UiThreadUtil.assertOnUiThread();
  25.  
  26. //开发模式,实现在线更新Bundle,晃动弹出调试菜单功能,这一部分属于调试功能流程。
  27. if (mUseDeveloperSupport && mJSMainModuleName != null) {
  28. final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
  29.  
  30. // If remote JS debugging is enabled,load from dev server.
  31. //判断是否处于开发模式,如果处于开发模式,则从Dev Server中获取JSBundle,如果不是则从文件获取
  32. if (mDevSupportManager.hasUpToDateJSBundleInCache() &&
  33. !devSettings.isRemoteJSDebugEnabled()) {
  34. // If there is a up-to-date bundle downloaded from server,
  35. // with remote JS debugging disabled,always use that.
  36. onJSBundleLoadedFromServer();
  37. } else if (mBundleLoader == null) {
  38. mDevSupportManager.handleReloadJS();
  39. } else {
  40. mDevSupportManager.isPackagerRunning(
  41. new PackagerStatusCallback() {
  42. @Override
  43. public void onPackagerStatusFetched(final boolean packagerIsRunning) {
  44. UiThreadUtil.runOnUiThread(
  45. new Runnable() {
  46. @Override
  47. public void run() {
  48. if (packagerIsRunning) {
  49. mDevSupportManager.handleReloadJS();
  50. } else {
  51. // If dev server is down,disable the remote JS debugging.
  52. devSettings.setRemoteJSDebugEnabled(false);
  53. recreateReactContextInBackgroundFromBundleLoader();
  54. }
  55. }
  56. });
  57. }
  58. });
  59. }
  60. return;
  61. }
  62.  
  63. //线上模式
  64. recreateReactContextInBackgroundFromBundleLoader();
  65. }
  66.  
  67. private void recreateReactContextInBackgroundFromBundleLoader() {
  68. //mJSCConfig可以在ReactNativeHost创建ReactInstanceManager时进行配置。mJSCConfig会通过JSCJavaScriptExecutor的
  69. //Native方法HybridData initHybrid(ReadableNativeArray jscConfig)传递到C++层。
  70. recreateReactContextInBackground(
  71. new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),mBundleLoader);
  72. }
  73.  
  74. private void recreateReactContextInBackground(
  75. JavaScriptExecutor.Factory jsExecutorFactory,JSBundleLoader jsBundleLoader) {
  76. UiThreadUtil.assertOnUiThread();
  77.  
  78. ReactContextInitParams initParams =
  79. new ReactContextInitParams(jsExecutorFactory,jsBundleLoader);
  80. if (mReactContextInitAsyncTask == null) {
  81. //初始化一个异步任务,创建ReactApplicationContext
  82. // No background task to create react context is currently running,create and execute one.
  83. mReactContextInitAsyncTask = new ReactContextInitAsyncTask();
  84. mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,initParams);
  85. } else {
  86. //创建ReactContext的后台任务已经开启,缓存initParams在队列中等待重新创建ReactContext
  87. // Background task is currently running,queue up most recent init params to recreate context
  88. // once task completes.
  89. mPendingReactContextInitParams = initParams;
  90. }
  91. }
  92.  
  93. }

整个代码调用链,最终开启异步任务ReactContextInitAsyncTask来创建上下文ReactApplicationContext。

ReactInstanceManager.createReactContextInBackground()
->ReactInstanceManager.recreateReactContextInBackground()
->ReactInstanceManager.recreateReactContextInBackgroundInner()
->ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()
->ReactInstanceManager.recreateReactContextInBackground(JavaScriptExecutor.Factory jsExecutorFactory,JSBundleLoader jsBundleLoader)
->ReactContextInitAsyncTask

方法启动了一个ReactContextInitAsyncTask的异步任务去执行的创建。

2.4 ReactInstanceManager.ReactContextInitAsyncTask.doInBackground(ReactContextInitParams… params)

  1. public class ReactInstanceManager {
  2.  
  3. /* * Task class responsible for (re)creating react context in the background. These tasks can only * be executing one at time,see {@link #recreateReactContextInBackground()}. */
  4. private final class ReactContextInitAsyncTask extends AsyncTask<ReactContextInitParams,Void,Result<ReactApplicationContext>> {
  5.  
  6. @Override
  7. protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
  8. // TODO(t11687218): Look over all threading
  9. // Default priority is Process.THREAD_PRIORITY_BACKGROUND which means we'll be put in a cgroup
  10. // that only has access to a small fraction of cpu time. The priority will be reset after
  11. // this task finishes: https://android.googlesource.com/platform/frameworks/base/+/d630f105e8bc0021541aacb4dc6498a49048ecea/core/java/android/os/AsyncTask.java#256
  12. Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
  13.  
  14. Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
  15. try {
  16. //利用getJsExecutorFactory创建jsExecutor,并传递到C++层。
  17. JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
  18. //异步执行createReactContext()方法,创建ReactContext
  19. return Result.of(createReactContext(jsExecutor,params[0].getJsBundleLoader()));
  20. } catch (Exception e) {
  21. // Pass exception to onPostExecute() so it can be handled on the main thread
  22. return Result.of(e);
  23. }
  24. }
  25. }

ReactContextInitAsyncTask的doInBackground()方法调用ReactInstanceManager.createReactContext()最终执行了ReactApplicationContext的创建。
我们重点来看看传入ReactInstanceManager.createReactContext()的2个参数:

  1. JSCJavaScriptExecutor jsExecutorJSCJavaScriptExecutor继承于JavaScriptExecutor,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用Native
  2. initHybrid()初始化C++层RNJSC通信的框架。
  3.  
  4. JSBundleLoader jsBundleLoader:缓存了JSBundle的信息,封装了上层加载JSBundle的相关接口,CatalystInstance通过其简介调用ReactBridge去加载JS文件,不同的场景会创建
  5. 不同的加载器,具体可以查看类JSBundleLoader

这两个参数是ReactInstanceManager.recreateReactContextInBackground()创建ReactContextInitAsyncTask传递进来的,有两个地方调用了ReactInstanceManager.recreateReactContextInBackground()
方法

接下来调用ReactInstanceManager.createReactContext(),真正开始创建ReactContext。

2.5 ReactInstanceManager.createReactContext( JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader)

  1. public class ReactInstanceManager {
  2.  
  3. /** * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set */
  4. private ReactApplicationContext createReactContext(
  5. JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader) {
  6. FLog.i(ReactConstants.TAG,"Creating react context.");
  7. ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
  8. //ReactApplicationContext是ReactContext的包装类。
  9. final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
  10. //创建JavaModule注册表Builder,用来创建JavaModule注册表,JavaModule注册表将所有的JavaModule注册到CatalystInstance中。
  11. NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
  12. reactContext,this,mLazyNativeModulesEnabled);
  13. //创建JavaScriptModule注册表Builder,用来创建JavaScriptModule注册表,JavaScriptModule注册表将所有的JavaScriptModule注册到CatalystInstance中。
  14. JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();
  15. if (mUseDeveloperSupport) {
  16. //如果处于开发模式,则设置NativeModuleCallExceptionHandler,将错误交由DevSupportManager处理(弹出红框,提示错误)。
  17. reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
  18. }
  19.  
  20. ReactMarker.logMarker(PROCESS_PACKAGES_START);
  21. Systrace.beginSection(
  22. TRACE_TAG_REACT_JAVA_BRIDGE,"createAndProcesscoreModulesPackage");
  23. try {
  24. //创建CoreModulesPackage实例,CoreModulesPackage里面封装了RN Framework核心功能包括:通信、调试等。
  25. CoreModulesPackage coreModulesPackage =
  26. new CoreModulesPackage(
  27. this,mBackBtnHandler,mUIImplementationProvider,mLazyViewManagersEnabled);
  28. //调用processPackage(0处理CoreModulesPackage,处理的过程就是把各自的Module添加到对应的注册表中。
  29. processPackage(coreModulesPackage,nativeModuleRegistryBuilder,jsModulesBuilder);
  30. } finally {
  31. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  32. }
  33.  
  34. // TODO(6818138): Solve use-case of native/js modules overriding
  35. for (ReactPackage reactPackage : mPackages) {
  36. Systrace.beginSection(
  37. TRACE_TAG_REACT_JAVA_BRIDGE,"createAndProcessCustomReactPackage");
  38. try {
  39. //循环处理我们在Application里注入的ReactPackage,处理的过程就是把各自的Module添加到对应的注册表中。
  40. processPackage(reactPackage,jsModulesBuilder);
  41. } finally {
  42. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  43. }
  44. }
  45. ReactMarker.logMarker(PROCESS_PACKAGES_END);
  46.  
  47. ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
  48. Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE,"buildNativeModuleRegistry");
  49. NativeModuleRegistry nativeModuleRegistry;
  50. try {
  51. //生成Java Module注册
  52. nativeModuleRegistry = nativeModuleRegistryBuilder.build();
  53. } finally {
  54. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  55. ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
  56. }
  57.  
  58. //查看外部是否设置NativeModuleCallExceptionHandler,它是在ReactInstanceManagerBuilder构建ReactInstanceManager是传递进来的
  59. //如果设置了则使用外部NativeModuleCallExceptionHandler,如果没有设置则使用DevSupportManager。
  60. NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
  61. ? mNativeModuleCallExceptionHandler
  62. : mDevSupportManager;
  63. //jsExecutor、nativeModuleRegistry、nativeModuleRegistry等各种参数处理好之后,开始构建CatalystInstanceImpl实例。
  64. CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
  65. .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
  66. .setJSExecutor(jsExecutor)
  67. .setRegistry(nativeModuleRegistry)
  68. //生成JS Module注册
  69. .setJSModuleRegistry(jsModulesBuilder.build())
  70. .setJSBundleLoader(jsBundleLoader)
  71. .setNativeModuleCallExceptionHandler(exceptionHandler);
  72.  
  73. ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
  74. // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
  75. Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE,"createCatalystInstance");
  76. final CatalystInstance catalystInstance;
  77. try {
  78. catalystInstance = catalystInstanceBuilder.build();
  79. } finally {
  80. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  81. ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
  82. }
  83.  
  84. if (mBridgeIdleDebugListener != null) {
  85. catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
  86. }
  87. if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JSC_CALLS)) {
  88. //调用CatalystInstanceImpl的Native方法把Java Registry转换为Json,再由C++层传送到JS层。
  89. catalystInstance.setGlobalVariable("__RCTProfileIsProfiling","true");
  90. }
  91.  
  92. //关联ReacContext与CatalystInstance
  93. reactContext.initializeWithInstance(catalystInstance);
  94. //通过CatalystInstance开始加载JS Bundle
  95. catalystInstance.runJSBundle();
  96.  
  97. return reactContext;
  98. }
  99. }

这个方法有点长,它主要做了以下事情:

  1. 1 创建JavaModule注册表与JavaScriptModule注册表,这两张表最后都交由CatalystInstance管理。
  2. 3 处理ReactPackage,将JavaModuleJavaScriptModule放进各自对应的注册表里。
  3. 3 通过上面jsExecutornativeModuleRegistryjsModulesRegistryjsBundleLoaderexceptionHandler等参数创建CatalystInstance实例。
  4. 4 关联ReactContextCatalystInstance,并将JS Bundle加载进来,等待ReactContextInitAsyncTask结束以后调用JS入口渲染页面

函数的最后调用CatalystInstance.runJSBundle()去加载JS Bundle,该加载过程的函数调用链如下所示:

  1. CatalystInstance.runJSBundle() -> JSBundleLoader.loadScript() -> CatalystInstance.jniLoadScriptFromAssets()/jniLoadScriptFromFile()
  2. -> CatalystInstance::jniLoadScriptFromAssets()/jniLoadScriptFromFile() -> Instance::loadScriptFromString()/loadScriptFromFile()
  3. -> NativeToJsBridge::loadApplication() -> JSCExecutor::loadApplicationScript()

最终由C++中的JSCExecutor.cpp完成了JS Bundle的加载,核心逻辑都在JSCExecutor.cpp中,这一块的内容我们后续的文章在详细分析,我们先来看看CatalystInstanceImpl的创建流程。

2.6 CatalystInstanceImpl.CatalystInstanceImpl( final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,final JavaScriptExecutor jsExecutor,final NativeModuleRegistry registry,final JavaScriptModuleRegistry jsModuleRegistry,final JSBundleLoader jsBundleLoader,NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler)

  1. public class CatalystInstanceImpl implements CatalystInstance {
  2.  
  3. private CatalystInstanceImpl(
  4. final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,final JavaScriptExecutor jsExecutor,final NativeModuleRegistry registry,final JavaScriptModuleRegistry jsModuleRegistry,final JSBundleLoader jsBundleLoader,NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
  5. FLog.w(ReactConstants.TAG,"Initializing React Xplat Bridge.");
  6.  
  7. //Native方法,用来创建JNI相关状态,并返回mHybridData。
  8. mHybridData = initHybrid();
  9.  
  10. //RN中的三个线程:Native Modules Thread、JS Thread、UI Thread,都是通过Handler来管理的。
  11. mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
  12. ReactQueueConfigurationSpec,new NativeExceptionHandler());
  13. mBridgeIdleListeners = new CopyOnWriteArrayList<>();
  14. mJavaRegistry = registry;
  15. mJSModuleRegistry = jsModuleRegistry;
  16. mJSBundleLoader = jsBundleLoader;
  17. mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
  18. mTraceListener = new JSProfilerTraceListener(this);
  19.  
  20. FLog.w(ReactConstants.TAG,"Initializing React Xplat Bridge before initializeBridge");
  21. //Native方法调用initializeBridge()方法,并创建BridgeCallback实例,初始化Bridge。
  22. initializeBridge(
  23. new BridgeCallback(this),jsExecutor,mReactQueueConfiguration.getJSQueueThread(),mReactQueueConfiguration.getNativeModulesQueueThread(),mJavaRegistry.getJavaModules(this),mJavaRegistry.getCxxModules());
  24. FLog.w(ReactConstants.TAG,"Initializing React Xplat Bridge after initializeBridge");
  25. mMainExecutorToken = getMainExecutorToken();
  26. }
  27.  
  28. //在C++层初始化通信桥ReactBridge
  29. private native void initializeBridge(
  30. ReactCallback callback,JavaScriptExecutor jsExecutor,MessageQueueThread jsQueue,MessageQueueThread moduleQueue,Collection<JavaModuleWrapper> javaModules,Collection<ModuleHolder> cxxModules);
  31. }

从CatalystInstanceImpl的构建过程可以看出,CatalystInstanceImpl是个封装管理类,封装了各种注册表,以及初始化JNI,我们来看看最后初始化Bridge传入的6个参数:

  1. ReactCallback callbackCatalystInstanceImpl的静态内部类ReactCallback,负责接口回调。
  2. JavaScriptExecutor jsExecutorJS执行器,将JS调用传递给C++层。
  3. MessageQueueThread jsQueue.getJSQueueThread():JS线程,通过mReactQueueConfiguration.getJSQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。
  4. MessageQueueThread moduleQueueNative线程,通过mReactQueueConfiguration.getNativeModulesQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。
  5. Collection<JavaModuleWrapper> javaModulesjava modules,来源于mJavaRegistry.getJavaModules(this)。
  6. Collection<ModuleHolder> cxxModules):c++ modules,来源于mJavaRegistry.getCxxModules()。

CatalystInstanceImpl被创建以后,便进行JS的加载。从上面第5步:ReactInstanceManager.createReactContext()方法可以知道,该函数会调
用CatalystInstanceImpl.runJSBundle()来加载JS Bundle。我们开看一下它的实现。

2.7 CatalystInstanceImpl.runJSBundle()

···java
public class CatalystInstanceImpl{

@Override
public void runJSBundle() {
Assertions.assertCondition(!mJSBundleHasLoaded,“JS bundle was already loaded!”);
mJSBundleHasLoaded = true;

  1. // incrementPendingJSCalls();
  2. //调用加载器加载JS Bundle,不同情况下加载器各不相同。
  3. mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
  4.  
  5. synchronized (mJSCallsPendingInitLock) {
  6. // Loading the bundle is queued on the JS thread,but may not have
  7. // run yet. It's safe to set this here,though,since any work it
  8. // gates will be queued on the JS thread behind the load.
  9. mAcceptCalls = true;
  10.  
  11. for (PendingJSCall call : mJSCallsPendingInit) {
  12. jniCallJSFunction(call.mExecutorToken,call.mModule,call.mMethod,call.mArguments);
  13. }
  14. mJSCallsPendingInit.clear();
  15. }
  16.  
  17. // This is registered after JS starts since it makes a JS call
  18. Systrace.registerListener(mTraceListener);

}
}
···

CatalystInstanceImpl.runJSBundle()会调用JSBundleLoader去加载JS Bundle,由于不同的情况可能会有不同的JSBundleLoader,我们假设用的是第一种:

  1. public abstract class JSBundleLoader {
  2.  
  3. /** * This loader is recommended one for release version of your app. In that case local JS executor * should be used. JS bundle will be read from assets in native code to save on passing large * strings from java to native memory. */
  4. public static JSBundleLoader createAssetLoader(
  5. final Context context,final String assetUrl) {
  6. return new JSBundleLoader() {
  7. @Override
  8. public String loadScript(CatalystInstanceImpl instance) {
  9. instance.loadScriptFromAssets(context.getAssets(),assetUrl);
  10. return assetUrl;
  11. }
  12. };
  13. }
  14.  
  15. }

可以看出,它会继续调用CatalystInstanceImpl.loadScriptFromAssets()方法去加载JS Bundle,该方法的实现如下所示:

2.8 CatalystInstanceImpl.loadScriptFromAssets(AssetManager assetManager,String assetURL)

  1. public class CatalystInstanceImpl {
  2.  
  3. /* package */ void loadScriptFromAssets(AssetManager assetManager,String assetURL) {
  4. mSourceURL = assetURL;
  5. jniLoadScriptFromAssets(assetManager,assetURL);
  6. }
  7.  
  8. private native void jniLoadScriptFromAssets(AssetManager assetManager,String assetURL);
  9.  
  10. }

CatalystInstanceImpl.java最终还是调用C++层的CatalystInstanceImpl.cpp去加载JS Bundle,我们去C++层看一下实现。

可以看出该方法最终调用Native方法jniLoadScriptFromAssets去加载JS Bundle,该方法的实现如下所示:

2.9 CatalystInstanceImpl::jniLoadScriptFromAssets(jni::alias_ref assetManager,const std::string& assetURL)

CatalystInstanceImpl.cpp

  1. void CatalystInstanceImpl::jniLoadScriptFromAssets(
  2. jni::alias_ref<JAssetManager::javaobject> assetManager,const std::string& assetURL) {
  3. const int kAssetsLength = 9; // strlen("assets://");
  4. //获取source js Bundle的路径名,这里默认的就是index.android.bundle
  5. auto sourceURL = assetURL.substr(kAssetsLength);
  6. //assetManager是Java层传递过来的AssetManager调用JSLoade.cpo里的extractAssetManager()方法,extractAssetManager()再
  7. //调用android/asset_manager_jni.h里的AAssetManager_fromJava()方法获取AAssetManager对象。
  8. auto manager = react::extractAssetManager(assetManager);
  9. //调用JSLoader.cpp的loadScriptFromAssets()方法读取JS Bundle里的内容
  10. auto script = react::loadScriptFromAssets(manager,sourceURL);
  11. //判断是不是unbundle命令打包,build.gradle默认里是bundle打包方式。
  12. if (JniJSModulesUnbundle::isUnbundle(manager,sourceURL)) {
  13. instance_->loadUnbundle(
  14. folly::make_unique<JniJSModulesUnbundle>(manager,sourceURL),std::move(script),sourceURL);
  15. return;
  16. } else {
  17. //bundle命令打包走次流程,instance_Instan.h中类的实例。
  18. instance_->loadScriptFromString(std::move(script),sourceURL);
  19. }
  20. }

接着会调用Instance.cpp的loadScriptFromString()方法去解析JS Bundle里的内容

2.10 Instance::loadScriptFromString(std::unique_ptr string,std::string sourceURL)

Instance.cpp

  1. @H_403_1352@void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,std::string sourceURL) {
  2. callback_->incrementPendingJSCalls();
  3. SystraceSection s("reactbridge_xplat_loadScriptFromString","sourceURL",sourceURL);
  4. //nativeToJsBridge_也是在Instance::initializeBridget()方法里初始化的,具体实现在NativeToJsBridge.cpp里。
  5. nativeToJsBridge_->loadApplication(nullptr,std::move(string),std::move(sourceURL));
  6. }

loadScriptFromString()进一步调用NativeToJsBridge.cpp的loadApplication()方法,它的实现如下所示:

2.11 NativeToJsBridge::loadApplication(std::unique_ptr unbundle,std::unique_ptr startupScript,std::string startupScriptSourceURL)

NativeToJsBridge.cpp

  1. void NativeToJsBridge::loadApplication(
  2. std::unique_ptr<JSModulesUnbundle> unbundle,std::unique_ptr<const JSBigString> startupScript,std::string startupScriptSourceURL) {
  3.  
  4. //获取一个MessageQueueThread,探后在线程中执行一个Task。
  5. runOnExecutorQueue(
  6. m_mainExecutorToken,[unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),startupScript=folly::makeMoveWrapper(std::move(startupScript)),startupScriptSourceURL=std::move(startupScriptSourceURL)]
  7. (JSExecutor* executor) mutable {
  8.  
  9. auto unbundle = unbundleWrap.move();
  10. if (unbundle) {
  11. executor->setJSModulesUnbundle(std::move(unbundle));
  12. }
  13.  
  14. //executor从runOnExecutorQueue()返回的map中取得,与OnLoad中的JSCJavaScriptExecutorHolder对应,也与
  15. //Java中的JSCJavaScriptExecutor对应。它的实例在JSExecutor.cpp中实现。
  16. executor->loadApplicationScript(std::move(*startupScript),std::move(startupScriptSourceURL));
  17. });
  18. }
  19.  
  20. 关于unbundle命令
  21.  
  22. <unbundle命令,使用方式和bundle命令完全相同。unbundle命令是在bundle命令的基础上增加了一项功能,除了生成整合JS文件index.android.bundle外,还会
  23. 生成各个单独的未整合JS文件(但会被优化),全部放在js-modules目录下,同时会生成一个名为UNBUNDLE的标识文件,一并放在其中。UNBUNDLE标识文件的前4个字节
  24. 固定为0xFB0BD1E5,用于加载前的校验。

我们先来看看这个函数的3个参数:

  1. std::unique_ptr<JSModulesUnbundle> unbundle:空指针,因为我们用的bundle方式打包。
  2. std::unique_ptr<const JSBigString> startupScriptbundle文件内容
  3. std::string startupScriptSourceURLbundle文件名。

函数进一步调用JSExecutor.cpp的loadApplicationScript()方法

2.12 JSCExecutor::loadApplicationScript(std::unique_ptr script,std::string sourceURL)

到了这个方法,就是去真正加载JS文件了。

JSExecutor.cpp

  1. void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) {
  2. SystraceSection s("JSCExecutor::loadApplicationScript",sourceURL);
  3.  
  4. ReactMarker::logMarker("RUN_JS_BUNDLE_START");
  5. String jsSourceURL(m_context,sourceURL.c_str());
  6.  
  7. // TODO t15069155: reduce the number of overrides here
  8. #ifdef WITH_FBJSCEXTENSIONS
  9. if (auto fileStr = dynamic_cast<const JSBigFileString *>(script.get())) {
  10. JSLoadSourceStatus jsStatus;
  11. auto bcSourceCode = JSCreateSourceCodeFromFile(fileStr->fd(),jsSourceURL,nullptr,&jsStatus);
  12.  
  13. switch (jsStatus) {
  14. case JSLoadSourceIsCompiled:
  15. if (!bcSourceCode) {
  16. throw std::runtime_error("Unexpected error opening compiled bundle");
  17. }
  18.  
  19. //使用Webkit JSC去解释执行JS
  20. evaluateSourceCode(m_context,bcSourceCode,jsSourceURL);
  21. //绑定bridge,核心就是通过getGlobalObject()将JS与C++通过Webkit jSC实现绑定
  22. bindBridge();
  23. flush();
  24.  
  25. ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
  26. ReactMarker::logMarker("RUN_JS_BUNDLE_END");
  27. return;
  28.  
  29. case JSLoadSourceErrorVersionMismatch:
  30. throw RecoverableError(explainLoadSourceStatus(jsStatus));
  31.  
  32. case JSLoadSourceErrorOnRead:
  33. case JSLoadSourceIsNotCompiled:
  34. // Not bytecode,fall through.
  35. break;
  36. }
  37. }
  38. #elif defined(__APPLE__)
  39. BundleHeader header;
  40. memcpy(&header,script->c_str(),std::min(script->size(),sizeof(BundleHeader)));
  41. auto scriptTag = parseTypeFromHeader(header);
  42.  
  43. if (scriptTag == ScriptTag::BCBundle) {
  44. using file_ptr = std::unique_ptr<FILE,decltype(&fclose)>;
  45. file_ptr source(fopen(sourceURL.c_str(),"r"),fclose);
  46. int sourceFD = fileno(source.get());
  47.  
  48. JSValueRef jsError;
  49. JSValueRef result = JSC_JSEvaluateBytecodeBundle(m_context,NULL,sourceFD,&jsError);
  50. if (result == nullptr) {
  51. formatandThrowJSException(m_context,jsError,jsSourceURL);
  52. }
  53. } else
  54. #endif
  55. {
  56. #ifdef WITH_FBSYSTRACE
  57. fbsystrace_begin_section(
  58. TRACE_TAG_REACT_CXX_BRIDGE,"JSCExecutor::loadApplicationScript-createExpectingAscii");
  59. #endif
  60.  
  61. ReactMarker::logMarker("loadApplicationScript_startStringConvert");
  62. String jsScript = jsStringFromBigString(m_context,*script);
  63. ReactMarker::logMarker("loadApplicationScript_endStringConvert");
  64.  
  65. #ifdef WITH_FBSYSTRACE
  66. fbsystrace_end_section(TRACE_TAG_REACT_CXX_BRIDGE);
  67. #endif
  68.  
  69. evaluateScript(m_context,jsScript,jsSourceURL);
  70. }
  71.  
  72. bindBridge();
  73. flush();
  74.  
  75. ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
  76. ReactMarker::logMarker("RUN_JS_BUNDLE_END");
  77. }

evaluateScript()方法调用Webkit jSC开始解析执行JS,并调用bindBridge()绑定bridge,我们这里主要分析的启动流程,先不分析JS渲染过程,先看看Bridge绑定
流程,bindBridge()的实现如下所示:

JSExecutor.cpp

  1. @H_403_1352@void JSCExecutor::bindBridge() throw(JSException) {
  2. SystraceSection s("JSCExecutor::bindBridge");
  3. if (!m_delegate || !m_delegate->getModuleRegistry()) {
  4. return;
  5. }
  6. auto global = Object::getGlobalObject(m_context);
  7. auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
  8. if (batchedBridgeValue.isUndefined()) {
  9. throwJSExecutionException("Could not get BatchedBridge,make sure your bundle is packaged correctly");
  10. }
  11.  
  12. auto batchedBridge = batchedBridgeValue.asObject();
  13. //callFunctionReturnFlushedQueue这些都是MessageQueue.js层里的方法
  14. m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
  15. m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
  16. //通过Webkit JSC获取MessageQueue.js的flushedQueue。
  17. m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
  18. m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
  19. }
  20.  
  21. @H_403_1352@void JSCExecutor::flush() {
  22. SystraceSection s("JSCExecutor::flush");
  23. if (!m_delegate) {
  24. // do nothing
  25. } else if (!m_delegate->getModuleRegistry()) {
  26. callNativeModules(Value::makeNull(m_context));
  27. } else {
  28. // If this is failing,chances are you have provided a delegate with a
  29. // module registry,but haven't loaded the JS which enables native function
  30. // queueing. Add BatchedBridge.js to your bundle,pass a nullptr delegate,
  31. // or make delegate->getModuleRegistry() return nullptr.
  32. CHECK(m_flushedQueueJS) << "Attempting to use native methods without loading BatchedBridge.js";
  33. //m_flushedQueueJS->callAsFunction({})等于调用MessageQueue.js的flushedQUeue()方法,即把JS层相关通信数据通过flushedQUeue()
  34. //返回给callNativeModules
  35. callNativeModules(m_flushedQueueJS->callAsFunction({}));
  36. }
  37. }
  38.  
  39. @H_403_1352@void JSCExecutor::callNativeModules(Value&& value) {
  40. SystraceSection s("JSCExecutor::callNativeModules");
  41. try {
  42. //把JS层相关通信数据转换为JSON格式
  43. auto calls = value.toJSONString();
  44. //m_delegate为JsToNativeBridge对象。
  45. m_delegate->callNativeModules(*this,folly::parseJson(calls),@H_403_1352@true);
  46. } catch (...) {
  47. std::string message = "Error in callNativeModules()";
  48. try {
  49. message += ":" + value.toString().str();
  50. } catch (...) {
  51. // ignored
  52. }
  53. std::throw_with_nested(std::runtime_error(message));
  54. }
  55. }

m_flushedQueueJS支线的是MessageQueue.js的flushedQueue()方法,此时JS已经被加载到队列中,等待Java层来驱动它。加载完JS后
ReactContextInitAsyncTask的后台任务执行完成,进入到异步任务的onPostExecute()方法继续

JS Bundle加载并解析完成后,ReactContextInitAsyncTask的后台任务完成,进入onPostExecute()方法,我们继续跟进它的实现。

当ReactContext被创建以后,变回继续执行ReactContextInitAsyncTask.onPostExecute()方法

2.13 ReactInstanceManager.ReactContextInitAsyncTask.onPostExecute(Result result)

  1. public class ReactInstanceManager {
  2.  
  3. /* * Task class responsible for (re)creating react context in the background. These tasks can only * be executing one at time,Result<ReactApplicationContext>> {
  4.  
  5. @Override
  6. protected void onPostExecute(Result<ReactApplicationContext> result) {
  7. try {
  8. //设置ReacContext
  9. setupReactContext(result.get());
  10. } catch (Exception e) {
  11. mDevSupportManager.handleException(e);
  12. } finally {
  13. mReactContextInitAsyncTask = null;
  14. }
  15.  
  16. // Handle enqueued request to re-initialize react context.
  17. if (mPendingReactContextInitParams != null) {
  18. recreateReactContextInBackground(
  19. mPendingReactContextInitParams.getJsExecutorFactory(),mPendingReactContextInitParams.getJsBundleLoader());
  20. mPendingReactContextInitParams = null;
  21. }
  22. }
  23. }

doInBackground()做完事情之后,onPostExecute()会去调用ReactInstanceManager.setupReactContext(),它的实现如下所示:

2.14 ReactInstanceManager.setupReactContext(ReactApplicationContext reactContext)

  1. public class ReactInstanceManager {
  2.  
  3. private void setupReactContext(ReactApplicationContext reactContext) {
  4. ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
  5. Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE,"setupReactContext");
  6. UiThreadUtil.assertOnUiThread();
  7. Assertions.assertCondition(mCurrentReactContext == null);
  8. mCurrentReactContext = Assertions.assertNotNull(reactContext);
  9. CatalystInstance catalystInstance =
  10. Assertions.assertNotNull(reactContext.getCatalystInstance());
  11.  
  12. //执行Native Java module的初始化
  13. catalystInstance.initialize();
  14. //重置DevSupportManager的ReactContext
  15. mDevSupportManager.onNewReactContextCreated(reactContext);
  16. //内存状态回调设置
  17. mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
  18. //复位生命周期
  19. moveReactContextToCurrentLifecycleState();
  20.  
  21. //mAttachedRootViews保存的是ReactRootView
  22. for (ReactRootView rootView : mAttachedRootViews) {
  23. attachMeasuredRootViewToInstance(rootView,catalystInstance);
  24. }
  25.  
  26. ReactInstanceEventListener[] listeners =
  27. new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
  28. listeners = mReactInstanceEventListeners.toArray(listeners);
  29.  
  30. for (ReactInstanceEventListener listener : listeners) {
  31. listener.onReactContextInitialized(reactContext);
  32. }
  33. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  34. ReactMarker.logMarker(SETUP_REACT_CONTEXT_END);
  35. }
  36.  
  37.  
  38. private void attachMeasuredRootViewToInstance(
  39. ReactRootView rootView,CatalystInstance catalystInstance) {
  40. Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE,"attachMeasuredRootViewToInstance");
  41. UiThreadUtil.assertOnUiThread();
  42.  
  43. //移除并重置所有页面UI元素
  44. // Reset view content as it's going to be populated by the application content from JS
  45. rootView.removeAllViews();
  46. rootView.setId(View.NO_ID);
  47.  
  48. //将ReactRootView作为根布局
  49. UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
  50. int rootTag = uiManagerModule.addMeasuredRootView(rootView);
  51. //设置相关
  52. rootView.setRootViewTag(rootTag);
  53.  
  54. //包装启动参数launchOptions与模块名jsAppModuleName
  55. @Nullable Bundle launchOptions与模块名 = rootView.getLaunchOptions();
  56. WritableMap initialProps = Arguments.makeNativeMap(launchOptions);
  57. String jsAppModuleName = rootView.getJSModuleName();
  58.  
  59. WritableNativeMap appParams = new WritableNativeMap();
  60. appParams.putDouble("rootTag",rootTag);
  61. appParams.putMap("initialProps",initialProps);
  62.  
  63. //启动流程入口:由Java层调用启动
  64. catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName,appParams);
  65. rootView.onAttachedToReactInstance();
  66. Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  67. }
  68. }

ReactInstanceManager.attachMeasuredRootViewToInstance()最终进入了RN应用的启动流程入口,调用catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName,appParams),
AppRegistry.class是JS层暴露给Java层的接口方法。它的真正实现在AppRegistry.js里,AppRegistry.js是运行所有RN应用的JS层入口,我们来看看它的实现:

2.15 AppRegistry.runApplication(appKey: string,appParameters: any)

AppRegistry.js

  1. //上面代码最终调用的就是这个函数
  2. runApplication(appKey: string,appParameters: any): void {
  3. const msg =
  4. 'Running application "' + appKey + '" with appParams: ' +
  5. JSON.stringify(appParameters) + '. ' +
  6. '__DEV__ === ' + String(__DEV__) +
  7. ',development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') +
  8. ',performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON');
  9. infoLog(msg);
  10. BugReporting.addSource('AppRegistry.runApplication' + runCount++,() => msg);
  11. invariant(
  12. runnables[appKey] && runnables[appKey].run,'Application ' + appKey + ' has not been registered.\n\n' +
  13. 'Hint: This error often happens when you\'re running the packager ' +
  14. '(local dev server) from a wrong folder. For example you have ' +
  15. 'multiple apps and the packager is still running for the app you ' +
  16. 'were working on before.\nIf this is the case,simply kill the old ' +
  17. 'packager instance (e.g. close the packager terminal window) ' +
  18. 'and start the packager in the correct app folder (e.g. cd into app ' +
  19. 'folder and run \'npm start\').\n\n' +
  20. 'This error can also happen due to a require() error during ' +
  21. 'initialization or failure to call AppRegistry.registerComponent.\n\n'
  22. );
  23. runnables[appKey].run(appParameters);
  24. },

到这里就会去调用JS进行组件渲染,再通过Java层的UIManagerModule将JS组件转换为Android组件,最终显示在ReactRootView上。

猜你在找的React相关文章