开始之前

  开始分析之前,新建一个名为 RnDemo 的空项目,RN 版本选择 0.58.1,查看项目自动为我们生成 MainActivity.java 和 MainApplication.java 文件,我们的分析就从这两个文件入手。

源码结构图

  "react-native": "^0.58.1", "react": "^16.6.3",

系统框架图

源码剖析

1、MainApplication

  继承 Application 并实现了 ReactApplication 接口,主要做一些 RN 的初始化操作。该接口要求创建一个 ReactNativeHost 对象。ReactNativeHost 对象,本身持有 ReactInstanceManager 对象。

public class MainApplication extends Application implements ReactApplication {// 实现 ReactApplication 接口,创建 ReactNativeHost 成员变量// 持有 ReactInstanceManager 实例,做一些初始化操作。private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {// 是否开启 dev 调试,及一些调试工具,比如 redbox(红盒),有时我们看到的报错@Overridepublic boolean getUseDeveloperSupport() {return BuildConfig.DEBUG;}// 返回 app 需要的 ReactPackage,添加需要加载的模块,// 这个地方就是我们在项目中添加依赖包时需要添加第三方 package 的地方@Override protected List<ReactPackage> getPackages() {@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;}@Overrideprotected String getJSMainModuleName() {return "index";}};@Overridepublic ReactNativeHost getReactNativeHost() {return mReactNativeHost;}@Overridepublic void onCreate() {super.onCreate();// SoLoader:加载 C++ 底层库,准备解析 JS。SoLoader.init(this, /* native exopackage */ false);}
}

  其中,ReactNativeHost 主要的工作就是创建 ReactInstanceManager,创建部分代码如下

public abstract class ReactNativeHost {protected ReactInstanceManager createReactInstanceManager() {// Builder 模式,创建 ReactInstanceManager 实例ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()// 设置应用上下文.setApplication(mApplication)// 设置应用的 jsBundle,可以传给 url 来使其从服务器拉去 jsBundle// 仅在 dev 下生效.setJSMainModulePath(getJSMainModuleName())// 是否开启 dev 模式.setUseDeveloperSupport(getUseDeveloperSupport())// 红盒回调.setRedBoxHandler(getRedBoxHandler()).setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())// 自定义 UI 实现机制,不会使用.setUIImplementationProvider(getUIImplementationProvider()).setJSIModulesPackage(getJSIModulePackage()).setInitialLifecycleState(LifecycleState.BEFORE_CREATE);// 添加 ReactPackage (就是我们复写的抽象方法)for (ReactPackage reactPackage : getPackages()) {builder.addPackage(reactPackage);}// 获取 js Bundle 的加载路径String jsBundleFile = getJSBundleFile();if (jsBundleFile != null) {builder.setJSBundleFile(jsBundleFile);} else {builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));}// 创建ReactInstanceManager reactInstanceManager = builder.build();return reactInstanceManager;}
}

2、MainActivity

  继承自 ReactActivity,ReactActivity 作为 JS 页面的真正容器

public class MainActivity extends ReactActivity {/*** Returns the name of the main component registered from JavaScript.* This is used to schedule rendering of the component.*/@Overrideprotected String getMainComponentName() {// 返回组件名,和 js 入口注册名字一致return "RnDemo";}
}
// 对应的 js 组件注册名字:
import { AppRegistry } from 'react-native'
// ...省略代码
AppRegistry.registerComponent("RnDemo", () => App);

3、ReactActivity

public abstract class ReactActivity extends AppCompatActivityimplements DefaultHardwareBackBtnHandler, PermissionAwareActivity {private final ReactActivityDelegate mDelegate;protected ReactActivity() {mDelegate = createReactActivityDelegate();}/*** Returns the name of the main component registered from JavaScript.* This is used to schedule rendering of the component.* e.g. "MoviesApp"*/protected @Nullable String getMainComponentName() {return null;}/*** Called at construction time, * override if you have a custom delegate implementation.*/protected ReactActivityDelegate createReactActivityDelegate() {return new ReactActivityDelegate(this, getMainComponentName());}...@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mDelegate.onCreate(savedInstanceState);}protected final ReactNativeHost getReactNativeHost() {return mDelegate.getReactNativeHost();}protected final ReactInstanceManager getReactInstanceManager() {return mDelegate.getReactInstanceManager();}protected final void loadApp(String appKey) {mDelegate.loadApp(appKey);}
}

  从以上代码可以看到,ReactActivity 全权委托给 ReactActivityDelegate 来处理,也就是说真正的实现是在 ReactActivityDelegate 类中进行的。

4、ReactActivityDelegate

public class ReactActivityDelegate {protected void onCreate(Bundle savedInstanceState) {// mMainComponentName 就是上面 ReactActivity.getMainComponentName()if (mMainComponentName!= null) {// 加载 app 页面loadApp(mMainComponentName);}// 双击判断工具类mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();}protected void loadApp(String appKey) {// 非空判断if (mReactRootView != null) {throw new IllegalStateException("Cannot loadApp while app is already running.");}// 创建 ReactRootView 作为根视图,它本质上是一个 FrameLayoutmReactRootView = createRootView();// 启动 RN 应用,并完成一些初始化设置mReactRootView.startReactApplication( // 分析getReactNativeHost().getReactInstanceManager(),appKey, getLaunchOptions());// 将 ReactRootView 作为 Activity 的显示 viewgetPlainActivity().setContentView(mReactRootView);}
}

  可以发现,ReactActivityDelegate(loadApp()) 主要做了三个工作:

  • 创建 ReactRootView 作为应用的根视图
  • startReactApplication 启动 RN 流程
  • 将 ReactRootView 作为 ReactActivity 的内容显示 view

5、ReactRootView

  ReactRootView 是个核心关键,本质上是一个 FrameLayout,进入 ReactRootView 类继续看一下启动 RN 的 startReactApplication() 方法,它接受四个参数:ReactInstanceManager,moduleName,initialProperties,initialUITemplate。

public void startReactApplication(ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle initialProperties,@Nullable String initialUITemplate) {// ...省略代码try {// 确保在 UI 线程执行UiThreadUtil.assertOnUiThread();// reactInstanceManager 实例,管理 React 实例mReactInstanceManager = reactInstanceManager;mJSModuleName = moduleName;mAppProperties = initialProperties;mInitialUITemplate = initialUITemplate;// 创建 RN 的上下文 ReactContextif (!mReactInstanceManager.hasStartedCreatingInitialContext()) {mReactInstanceManager.createReactContextInBackground(); // 分析}// 宽高计算完成后添加布局监听attachToReactInstanceManager();} finally {Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);}}

6、ReactInstanceManger

进入 ReactInstanceManger 类看一下 createReactContextInBackground() 方法。

/*** 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.*/@ThreadConfined(UI)public void createReactContextInBackground() {// 省略。。。// 仅在应用首次启动时调用,防止开发人员意外的创建其他应用mHasStartedCreatingInitialContext = true;recreateReactContextInBackgroundInner(); // 分析}

7、recreateReactContextInBackgroundInner

  createReactContextInBackground 方法仅会在首次启动时调用,重新加载 (reloaded)app 时,会调用 recreateReactContextInBackground(),两个方法都会调用 recreateReactContextInBackgroundInner()。

@ThreadConfined(UI)private void recreateReactContextInBackgroundInner() {//...省略// // UI 线程UiThreadUtil.assertOnUiThread();// 开发模式,实现在线更新 Bundle,// 晃动弹出调试菜单等功能,这一部分属于调试功能流程。if (mUseDeveloperSupport && mJSMainModulePath != null) {final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();// If remote JS debugging is enabled, load from dev server.if (mDevSupportManager.hasUpToDateJSBundleInCache() &&!devSettings.isRemoteJSDebugEnabled()) {// If there is a up-to-date bundle downloaded from server,// with remote JS debugging disabled, always use that.// 调试模式,从服务器加载 jsBundleonJSBundleLoadedFromServer(null);return;}if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {// 加载服务 bundleif (mBundleLoader == null) {mDevSupportManager.handleReloadJS();} else {mDevSupportManager.isPackagerRunning(new PackagerStatusCallback() {@Overridepublic void onPackagerStatusFetched(final boolean packagerIsRunning) {UiThreadUtil.runOnUiThread(new Runnable() {@Overridepublic void run() {if (packagerIsRunning) {mDevSupportManager.handleReloadJS();} else {// If dev server is down, disable the remote JS debugging.devSettings.setRemoteJSDebugEnabled(false);recreateReactContextInBackgroundFromBundleLoader();}}});}});}return;}}// 加载本地 bundlerecreateReactContextInBackgroundFromBundleLoader(); // 分析}@ThreadConfined(UI)private void recreateReactContextInBackgroundFromBundleLoader() {recreateReactContextInBackground(new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),mBundleLoader); // 分析}

8、recreateReactContextInBackground

  recreateReactContextInBackgroundFromBundleLoader() 方法继续向下调用 recreateReactContextInBackground() 方法。

@ThreadConfined(UI)private void recreateReactContextInBackground(JavaScriptExecutorFactory jsExecutorFactory, // C++ 和 JS 双向通信的中转站JSBundleLoader jsBundleLoader) { // bundle 加载器,根据 ReactNativeHost 中的配置决定从哪里加载 bundle 文件UiThreadUtil.assertOnUiThread();// 创建 ReactContextInitParams 对象final ReactContextInitParams initParams = new ReactContextInitParams(jsExecutorFactory,jsBundleLoader);if (mCreateReactContextThread == null) {// 在 newThread 实例化 ReactContextrunCreateReactContextOnNewThread(initParams);} else {mPendingReactContextInitParams = initParams;}}// runCreateReactContextOnNewThread() 方法中内容
final ReactApplicationContext reactApplicationContext =createReactContext(initParams.getJsExecutorFactory().create(),initParams.getJsBundleLoader()); // 分析
}

  在 runCreateReactContextOnNewThread() 方法中,我们看到是 ReactInstanceManager.createReactContext() 方法最终创建了 ReactApplicationContext,我们继续看 createReactContext() 方法,有关此方法的2个参数:

  • JSCJavaScriptExecutor jsExecutor:JSCJavaScriptExecutor 继承于JavaScriptExecutor,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用 Native 方法 initHybrid() 初始化 C++ 层 RN 与 JSC 通信的框架
  • JSBundleLoader jsBundleLoader:缓存了 JSBundle 的信息,封装了上层加载 JSBundle 的相关接口,CatalystInstance 通过其间接调用 ReactBridge 去加载 JS 文件,不同的场景会创建不同的加载器,根据 ReactNativeHost 中的配置决定从哪里加载 bundle 文件。

9、createReactContext

private ReactApplicationContext createReactContext(JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader) {// ReactApplicationContext 是 reactContext 的包装类final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null? mNativeModuleCallExceptionHandler: mDevSupportManager;reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);// 创建 JavaModule 注册表 Builder,用来创建 JavaModule 注册表,// JavaModule 注册表将所有的 JavaModule 注册到 CatalystInstance 中。NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);// jsExecutor、nativeModuleRegistry、jsBundleLoader 等各种参数处理好之后,// 开始构建 CatalystInstanceImpl 实例。CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder().setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()).setJSExecutor(jsExecutor) // js 执行通信类.setRegistry(nativeModuleRegistry) // java 模块注册表.setJSBundleLoader(jsBundleLoader) // bundle 加载器.setNativeModuleCallExceptionHandler(exceptionHandler); // 异常处理器final CatalystInstance catalystInstance;try {catalystInstance = catalystInstanceBuilder.build();} finally {Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);}if (mJSIModulePackage != null) {catalystInstance.addJSIModules(mJSIModulePackage.getJSIModules(reactContext, catalystInstance.getJavaScriptContextHolder()));}if (mBridgeIdleDebugListener != null) {catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);}if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {// 调用 CatalystInstanceImpl 的 Native 方法把 Java Registry 转换为 Json,// 再由 C++ 层传送到 JS 层。catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");}// 通过 CatalystInstance 开始加载 JS BundlecatalystInstance.runJSBundle(); // 分析// 关联 ReacContext 与 CatalystInstancereactContext.initializeWithInstance(catalystInstance);return reactContext;}

  这段代码比较长,它主要做了这几件事:

  • 创建 JavaModule 注册表和 JavaScriptModule 注册表,交给 CatalystInstance 管理。
  • 处理 ReactPackage,将各自的 Module 放入对应的注册表中
  • 通过上面的各个参数创建 CatalystInstance 实例
  • CatalystInstance 关联 ReactContext,开始加载 JS Bundle

  createReactContext 方法中用 catalystInstance.runJSBundle() 来加载 JS bundle。

@Overridepublic void runJSBundle() {// ...省略代码// 调用加载器加载 JS Bundle,不同情况下加载器不同。分析mJSBundleLoader.loadScript(CatalystInstanceImpl.this);// ...省略代码
}

  调用栈如下:
CatalystInstanceImpl.runJSBundle() -> JSBundleLoader.loadScript() -> CatalystInstanceImpl.loadScriptFromAssets()/loadScriptFromFile() -> CatalystInstanceImpl.jniLoadScriptFromAssets()/jniLoadScriptFromFile()-> CatalystInstanceImpl::jniLoadScriptFromAssets()/jniLoadScriptFromFile() -> Instance::loadScriptFromString()/loadScriptFromFile()-> NativeToJsBridge::loadApplication() -> JSCExecutor::loadApplicationScript()

  我们假设调用了 loadScriptFromAssets 方法,(本地)可以看出该方法最终调用 Native 方法 jniLoadScriptFromAssets 去加载 JS Bundle

@Overridepublic void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {mSourceURL = assetURL;jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);}private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);

10、CatalystInstanceImpl.java

  CatalystInstanceImpl.java 最终还是调用 C++ 层的 CatalystInstanceImpl.cpp 去加载 JS Bundle。 CatalystInstance 是 ReactNative 应用 Java 层、C++ 层、JS 层通信总管理类,总管 Java 层、JS 层核心 Module 映射表与回调,三端通信的入口与桥梁。

public class CatalystInstanceImpl implements CatalystInstance {private CatalystInstanceImpl(final ReactQueueConfigurationSpec reactQueueConfigurationSpec,final JavaScriptExecutor jsExecutor,final NativeModuleRegistry nativeModuleRegistry,final JSBundleLoader jsBundleLoader,NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {// Native 方法,用来创建 JNI 相关状态,并返回 mHybridDatamHybridData = initHybrid();// RN 中的三个线程:Native Modules Thread、// JS Thread、UI Thread,都是通过 Handler 来管理的。mReactQueueConfiguration = ReactQueueConfigurationImpl.create(reactQueueConfigurationSpec,new NativeExceptionHandler());mBridgeIdleListeners = new CopyOnWriteArrayList<>();mNativeModuleRegistry = nativeModuleRegistry;// 创建 JavaScriptModule 注册表mJSModuleRegistry = new JavaScriptModuleRegistry();mJSBundleLoader = jsBundleLoader;mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();mTraceListener = new JSProfilerTraceListener(this);// 在 C++ 层初始化通信桥 Bridge。initializeBridge(new BridgeCallback(this),jsExecutor,mReactQueueConfiguration.getJSQueueThread(),mNativeModulesQueueThread,mNativeModuleRegistry.getJavaModules(this),mNativeModuleRegistry.getCxxModules());mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());}// 在 C++ 层初始化通信桥 ReactBridgeprivate native void initializeBridge(ReactCallback callback,JavaScriptExecutor jsExecutor,MessageQueueThread jsQueue,MessageQueueThread moduleQueue,Collection<JavaModuleWrapper> javaModules,Collection<ModuleHolder> cxxModules);
}

  从 CatalystInstanceImpl 的构建过程可以看出,CatalystInstanceImpl 是个封装管理类,封装了各种注册表,以及初始化 JNI。

11、CatalystInstanceImpl.cpp

  在项目的 node_modules/react-native/ReactAndroid/src/main/jni/react/jni 可以找到 CatalystInstanceImpl.cpp。

void CatalystInstanceImpl::jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,const std::string& assetURL,bool loadSynchronously) {const int kAssetsLength = 9; // strlen("assets://");// 获取 source js Bundle 的路径名auto sourceURL = assetURL.substr(kAssetsLength);// assetManager 是 Java 层传递过来的 AssetManager,// 调用 JSLoader.cpp 里的 extractAssetManager() 方法,// extractAssetManager() 再调用 android/asset_manager_jni.h// 里的 AssetManager_fromJava() 方法获取 AssetManager 对象。auto manager = extractAssetManager(assetManager);// 调用 JSloader.cpp 的 loadScriptFromAssets 方法,// 读取 js Bundle 里面的内容auto script = loadScriptFromAssets(manager, sourceURL);// unbundle 命令打包判断,build.gradle 默认是 bundle 打包方式。if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));instance_->loadRAMBundle(std::move(registry),std::move(script),sourceURL,loadSynchronously);return;} else if (Instance::isIndexedRAMBundle(&script)) {instance_->loadRAMBundleFromString(std::move(script), sourceURL);} else {// bundle 命令打包走此流程,instance_ 是 Instance.h 中类的实例instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);}
}

  关于 unbundle 命令
  unbundle 命令,使用方式和 bundle 命令完全相同。unbundle 命令是在 bundle 命令的基础上增加了一项功能,除了生成整合 JS 文件 index.android.bundle 外,还会生成各个单独的未整合 JS 文件(但会被优化),全部放在 js-modules 目录下,同时会生成一个名为 UNBUNDLE 的标识文件,一并放在其中。UNBUNDLE 标识文件的前4个字节固定为 0xFB0BD1E5,用于加载前的校验。

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

void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,std::string sourceURL,bool loadSynchronously) {if (loadSynchronously) {loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));} else {loadApplication(nullptr, std::move(string), std::move(sourceURL)); // 分析}
}void Instance::loadApplicationSync(std::unique_ptr<JSModulesUnbundle> unbundle,std::unique_ptr<const JSBigString> string,std::string sourceURL) {std::unique_lock<std::mutex> lock(m_syncMutex);m_syncCV.wait(lock, [this] { return m_syncReady; });// nativeToJsBridge_ 也是在 Instance::initializeBridget() 方法里初始化的// ,具体实现在 NativeToJsBridge.cpp 里。 nativeToJsBridge_->loadApplicationSync(std::move(unbundle), std::move(string), std::move(sourceURL));
}

12、NativeToJsBridge.cpp

  在项目node_modules/react-native/ReactCommon 的 cxxReact 的 NativeToJsBridge.cpp 文件。最终由 C++ 中的 JSCExecutor.cpp 完成了 JS Bundle 的加载,核心逻辑都在 JSCExecutor.cpp 中。

void NativeToJsBridge::loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,std::unique_ptr<const JSBigString> startupScript,std::string startupScriptSourceURL) {// 获取一个 MessageQueueThread,然后在线程中执行一个 Task。runOnExecutorQueue([this,bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)),startupScript=folly::makeMoveWrapper(std::move(startupScript)),startupScriptSourceURL=std::move(startupScriptSourceURL)](JSExecutor* executor) mutable {auto bundleRegistry = bundleRegistryWrap.move();if (bundleRegistry) {executor->setBundleRegistry(std::move(bundleRegistry));}try {// executor 也与 Java 中的 JSCJavaScriptExecutor 对应。// 它的实例在 JSIExecutor.cpp 中实现。executor->loadApplicationScript(std::move(*startupScript),std::move(startupScriptSourceURL)); // 分析} catch (...) {m_applicationScriptHasFailure = true;throw;}});
}

13、JSCExecutor.cpp

void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) {SystraceSection s("JSIExecutor::loadApplicationScript");//...//// 解释执行 JSruntime_->evaluateJavaScript(std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);flush(); // 分析//...//
}
void JSCExecutor::flush() {...// 绑定 bridge,核心就是通过 getGlobalObject() 将 JS 与 C++// 通过 Webkit jSC 实现绑定bindBridge();// 返回给 callNativeModulescallNativeModules(m_flushedQueueJS->callAsFunction({}));...
}
void JSCExecutor::callNativeModules(Value&& value) {...// 把 JS 层相关通信数据转换为 JSON 格式auto calls = value.toJSONString();// m_delegate 为 JsToNativeBridge 对象。m_delegate->callNativeModules(*this, folly::parseJson(calls), true);...
}

14、ReactInstanceManager

  flushedQueueJS 执行的是 MessageQueue.js 的 flushedQueue() 方法,此时 JS 已被加载到队列中等待 Java 层来驱动它。加载完 JS 后,返回 reactApplicationContext,继续跟进它的实现。

@ThreadConfined(UI)private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {mCreateReactContextThread =new Thread(null,new Runnable() {@Overridepublic void run() {// 省略部分代码try {final ReactApplicationContext reactApplicationContext =createReactContext(initParams.getJsExecutorFactory().create(),initParams.getJsBundleLoader());mCreateReactContextThread = null;Runnable setupReactContextRunnable =new Runnable() {@Overridepublic void run() {try {setupReactContext(reactApplicationContext); // 分析} catch (Exception e) {mDevSupportManager.handleException(e);}}};reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);} catch (Exception e) {mDevSupportManager.handleException(e);}}},"create_react_context");}

  回到 ReactInstanceManager 类的 runCreateReactContextOnNewThread() 方法中,看到 setupReactContext() 方法,这就是加载 JS Bundle 之后执行的代码

private void setupReactContext(final ReactApplicationContext reactContext) {synchronized (mAttachedReactRoots) {CatalystInstance catalystInstance =Assertions.assertNotNull(reactContext.getCatalystInstance());// Native Java module 的初始化catalystInstance.initialize();mDevSupportManager.onNewReactContextCreated(reactContext);mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);// 复位生命周期moveReactContextToCurrentLifecycleState();// 遍历 ReactRootViewfor (ReactRoot reactRoot : mAttachedReactRoots) {// 遍历 ReactRootView  分析attachRootViewToInstance(reactRoot); // 分析}}//...省略//}

  可以看到 attachRootViewToInstance(ReactRootView) 方法,进入后:

private void attachRootViewToInstance(final ReactRootView rootView) {UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, rootView.getUIManagerType());@Nullable Bundle initialProperties = rootView.getAppProperties();// 将 ReactRootView 作为根布局final int rootTag = uiManagerModule.addRootView(rootView,initialProperties == null ?new WritableNativeMap() : Arguments.fromBundle(initialProperties),rootView.getInitialUITemplate());rootView.setRootViewTag(rootTag);// 启动流程的入口 分析rootView.runApplication();// 省略部分代码UiThreadUtil.runOnUiThread(new Runnable() {@Overridepublic void run() {rootView.onAttachedToReactInstance();}});}
@Overridepublic void runApplication() {try {if (mReactInstanceManager == null || !mIsAttachedToInstance) {return;}ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();if (reactContext == null) {return;}CatalystInstance catalystInstance = reactContext.getCatalystInstance();WritableNativeMap appParams = new WritableNativeMap();appParams.putDouble("rootTag", getRootViewTag());@Nullable Bundle appProperties = getAppProperties();if (appProperties != null) {appParams.putMap("initialProps", Arguments.fromBundle(appProperties));}if (getUIManagerType() == FABRIC) {appParams.putBoolean("fabric", true);}mShouldLogContentAppeared = true;String jsAppModuleName = getJSModuleName();// 分析catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);} finally {Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);}}

15、AppRegistry.js

  catalystInstance.getJSModule(AppRegistry.class)
  AppRegistry.class 是 JS 层暴露给 Java 层的接口方法,它的真正实现在 AppRegistry.js 里,AppRegistry.js 是运行所有 RN 应用的 JS 层入口。

/**- JS module interface - main entry point for launching React application for a given key.*/// AppRegistry.java
public interface AppRegistry extends JavaScriptModule {void runApplication(String appKey, WritableMap appParameters);void unmountApplicationComponentAtRootTag(int rootNodeTag);void startHeadlessTask(int taskId, String taskKey, WritableMap data);
}

  上面代码最终调用的 AppRegistry.js 中的这个函数

/**- Loads the JavaScript bundle and runs the app.-  4. See http://facebook.github.io/react-native/docs/appregistry.html#runapplication*/runApplication(appKey: string, appParameters: any): void {const msg ='Running application "' +appKey +'" with appParams: ' +JSON.stringify(appParameters) +'. ' +'__DEV__ === ' +String(__DEV__) +', development-level warning are ' +(__DEV__ ? 'ON' : 'OFF') +', performance optimizations are ' +(__DEV__ ? 'OFF' : 'ON');infoLog(msg);BugReporting.addSource('AppRegistry.runApplication' + runCount++,() => msg,);invariant(runnables[appKey] && runnables[appKey].run,'Application ' +appKey +' has not been registered.\n\n' +"Hint: This error often happens when you're running the packager " +'(local dev server) from a wrong folder. For example you have ' +'multiple apps and the packager is still running for the app you ' +'were working on before.\nIf this is the case, simply kill the old ' +'packager instance (e.g. close the packager terminal window) ' +'and start the packager in the correct app folder (e.g. cd into app ' +"folder and run 'npm start').\n\n" +'This error can also happen due to a require() error during ' +'initialization or failure to call AppRegistry.registerComponent.\n\n',);SceneTracker.setActiveScene({name: appKey});runnables[appKey].run(appParameters);},

  基本到这,就会去调用 JS 进行组件渲染,再通过 Java 层的 UIManagerModule 将 JS 组件转换为 Android 组件,最终显示在 ReactRootView 上,即完成启动过程。

简单总结

  启动流程可分以下几步:

  • 在程序启动的时候,也就是 ReactActivity 的 onCreate() 函数中,我们会去创建一个 ReactInstanceManager 对象,ReactInstanceManager 用于管理生命周期,管理 ReactRootView,以及一些配置等。
  • ReactRootView 作为应用的根视图,通过调用 startReactApplication() 方法启动应用。
  • RN 应用页面渲染前,需要先创建上下文 ReactContext, 它的创建流程在异步任务 ReactContextInitAsyncTask 负责来完成这个任务。
  • ReactContextInitAsyncTask 在后台 ReactContextInitAsyncTask.doInBackground() 执行 ReactContext 的创建,创建 ReactContext 的过程中,会依据 ReactPackage 创建 JavaScriptModuleRegistry 与 NativeModuleRegistry 注册表以及它们的管理类 CatalystInstanceImpl,同时创建 JS、Native 与 UI 线程队列,并最终调用 CatalystInstanceImpl.runJSBundle() 去异步加载 JS Bundle 文件**(C++层)**
  • 后台任务执行完成后,在 ReactContextInitAsyncTask.onPostExecute() 会调用 ReactInstanceManager.setupReactContext() 设置创建好的 ReactContext,并将 ReactRootView 加载进来,并调用 RN 应用的 JS 入口 APPRegistry 来启动应用。
  • JS 层找到已经注册的对应的启动组件,执行 renderApplication() 来渲染整个应用。

------至所有正在努力奋斗的程序猿们!加油!!
有码走遍天下 无码寸步难行
1024 - 梦想,永不止步!
爱编程 不爱Bug
爱加班 不爱黑眼圈
固执 但不偏执
疯狂 但不疯癫
生活里的菜鸟
工作中的大神
身怀宝藏,一心憧憬星辰大海
追求极致,目标始于高山之巅
一群怀揣好奇,梦想改变世界的孩子
一群追日逐浪,正在改变世界的极客
你们用最美的语言,诠释着科技的力量
你们用极速的创新,引领着时代的变迁

——乐于分享,共同进步,欢迎补充
——Treat Warnings As Errors
——Any comments greatly appreciated
——Talking is cheap, show me the code
——诚心欢迎各位交流讨论!QQ:1138517609
——CSDN:https://blog.csdn.net/u011489043
——简书:https://www.jianshu.com/u/4968682d58d1
——GitHub:https://github.com/selfconzrr

React Native 启动流程 源码剖析相关推荐

  1. 文化袁探索专栏——React Native启动流程

    文化袁探索专栏--Activity.Window和View三者间关系 文化袁探索专栏--View三大流程#Measure 文化袁探索专栏--View三大流程#Layout 文化袁探索专栏--消息分发机 ...

  2. 游戏思考17:寻路引擎recast和detour学习二:recast导航网格生成流程\源码剖析流程\局限性,附录计算点线面举例代码

    一.recastnavigation使用介绍 1)模式选择 Solo Mesh:单块生成 Tile Mesh:分块生成 Temp Obstacles:分块并支持动态阻挡 这里测试的话选单块生成 2)模 ...

  3. react native 0.50 源码解析 再出发 持续更新

    1.核心类 1.1 RCTRootView 一个RCTRootView持有一个RCTBridge成员变量 RCTRootView : UIViewRCTBridge *bridge;UIViewCon ...

  4. 【ElasticSearch】Es 启动流程 源码分析

    文章目录 1. 概述 2. start方法 2.1 启动生命周期相关的组件 2.2 启动IndicesService 2.3 IndicesClusterStateService启动 2.4 Snap ...

  5. CC00055.hadoop——|HadoopMapReduce.V27|——|Hadoop.v27|源码剖析|DataNode启动流程|

    一.[源码剖析之DataNode启动流程] :DataNode 启动流程 ### --- datanode的Main Class是DataNode,先找到DataNode.main()public c ...

  6. bluetoothd源码剖析(一)启动流程

    蓝牙系列: bluez调试笔记_weixin_41069709的博客-CSDN博客_bluezbluez移植https://blog.csdn.net/weixin_41069709/article/ ...

  7. 4.2.10 Kafka源码剖析, 阅读环境搭建, broker启动流程, topic创建流程, Producer生产者流程, Consumer消费者流程,

    目录 4.1 Kafka源码剖析之源码阅读环境搭建 4.1.1 安装配置Gradle 4.1.2 Scala的安装和配置 4.1.3 Idea配置 4.1.4 源码操作 4.2 Kafka源码剖析之B ...

  8. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  9. Spring Boot 2.x 启动全过程源码分析(上)入口类剖析

    转载自   Spring Boot 2.x 启动全过程源码分析(上)入口类剖析 Spring Boot 的应用教程我们已经分享过很多了,今天来通过源码来分析下它的启动过程,探究下 Spring Boo ...

最新文章

  1. 内存性能参数详解(转载)
  2. CYQ.Data 数据框架系列索引
  3. Nacos 1.3.0 发布,一个修炼内功的版本:全新内核构建!
  4. assert self.binded
  5. unity, 非public变量需要加[SerializeField]才能序列化
  6. c++ 中this 和 *this区别
  7. 函数传参string_JavaScript 高阶函数入门浅析
  8. 联想e431笔记本更改硬盘模式bios设置的详细教程
  9. 想辞职专心做自媒体可以吗?有哪些建议吗?
  10. C#中Abstract和Virtual
  11. python qq群管理_Python selenium 加载并保存QQ群成员,去除其群主、管理员信息的示例代码...
  12. 使用python PIL 模块合成图片
  13. Typhoon-v1.02渗透笔记
  14. 计算机禁用网络后怎么打开,无线网关,教您笔记本无线网络禁用后怎么开启
  15. windows录屏_Windows电脑怎么录制屏幕?查看电脑自动录屏方法
  16. 计算机考研考线代和概率论吗,考研数一数二数三的区别有哪些
  17. FileReader 和 FileWriter(Second)
  18. BroadCastReceiver 简介
  19. 03.Hadoop之HDFS
  20. Java自学资料!靠着这份面试题跟答案

热门文章

  1. MacBook Pro外接显示器竖屏显示
  2. Win10如何修改 开始菜单,并添加 磁贴
  3. 未连接到互联网代理服务器出现问题,或者地址有误,该如何解决?
  4. (小白)Excel学习笔记
  5. java模拟器ios版安装失败,iOS 在模拟器上安装 Debug 调试包(.app)
  6. 关于蓝桥杯比赛的参赛心得
  7. Excel计算开始与结束时间之间的小时/分钟/秒数
  8. [Python核心技术与实战学习] 18 单元测试unittest 库
  9. 最全的有道云笔记实用功能大盘点!PS:遇到优质的文章想收藏下来怎么办?在这里您就可以找到答案!
  10. 日本用计算机模拟核试验,法国:将用超级计算机模拟核试验