React-Native原理浅析

一、整体部分

整体看,分为三个部分
github

  • Java层,即Android层,提供了Android的渲染工具及其他工具。
  • C++层,完成Java层与JS层的通信,与JS代码运行层。
  • JS层,即JavaScript层,提供给JS层的开发人员提供环境。

重要角色:

  • ReactActivityDelegate: 是ReactActivity界面类的生命周期管理类。
  • ReactInstanceManager: 是RN应用的管理总类,创建了ReactContextCatalystInstance等类,解析ReactPackage生成映射表,配合ReactRootView管理控件等功能。
  • ReactContext: 继承与ContextWrapper,是RN应用中使用的上下文,可以使用getContext()获取,来访问RN核心类。
  • CatalystInstance: 是RN应用Java层、C++层、JS层的通信总管理类,管理Java层与JS层核心Module映射表与回调。
  • ReactRootView: 启动入口类,负责监听及分发事件、渲染元素。

  • JavaScriptModule: JsModule,负责JS到Java的映射调用格式声明,由CatalystInstance管理。

  • NativeModule: JavaModule,负责Java到JS的映射调用格式声明,也由CatalystInstance管理。

  • JavascriptModuleRegistry: JsModule映射表,负责将javaModule注册到CatalystInstance,通过Java动态代理调用JS。

  • NativeModuleRegistry: JavaModule映射表,相反,暴露Java接口给JS。

以上为框架中重要的角色,当真正渲染UI时,使用的时Native代码层,RN的作用就是吧JS代码映射成Native代码来实现两端通信。

一、ReactActivity

对于Android开发者,程序入口为Activity的继承类。

  • ReactRootView:RN入口,也是界面对象。
  • ReactActivityDelegate:ReactActivity的生命周期及其他类的管理类。
  • ReactInstanceManager:构建React环境,发送事件到JS层。
  • ReactPackage:配置App需要加载的模块,添加的包会在Application文件中配置。

onCreate

ReactActivityDelegate中会在ReactActivity调用onCreate()的生命周期中调用loadApp()函数。

protected void loadApp(String appKey) {
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

...

public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}

github

getReactInstanceManager()

ReactinstanceManager对象也是在ReactActivityDelegate中创建。

public ReactInstanceManager getReactInstanceManager() {
return mReactDelegate.getReactInstanceManager();
}

ReactinstanceManager调用createReactContext()创建了CatalystInstance。加载指定JS文件后,就会启动App,后面会加以描述。
注意这里的getReactInstanceManager()创建的ReactInstanceManager对象。因为里面会有许多重要工作。
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
ReactInstanceManagerBuilder builder =
ReactInstanceManager.builder()
.setApplication(mApplication)
.setJSMainModulePath(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setUIImplementationProvider(getUIImplementationProvider())
.setJSIModulesPackage(getJSIModulePackage())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);

for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}

String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
ReactInstanceManager reactInstanceManager = builder.build();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
}

1.处理Modules Package
2.创建CatalystInstance需要的builder
3.获取JS Bundle文件加载路径

对于RN,所有的Native组件与JS组件都需要分别继承NativeModuleJavaScriptModule类,并且都需要在CatalystInstance中注册。Native组件与JS组件都被封装进相应的ReactPackage中。

NativeModule:负责向JS端提供可用的接口,这些接口由Native端实现。内部的createNativeModules()createViewManagers()负责完成对组件的接口与UI的创建工具。
JavaScriptModule:负责向Native端提供可用的接口,这些接口由JS端实现。内部的createJSModules()来返回内部包含的内容。注意该接口已于0.47版本删除

在创建ReactInstanceManager时会创建CoreModulesPackage对象。

github

CoreModulesPackage

CoreModulesPackage:定义并组装了核心框架模块(如UIManager),通常用于需要与其他模块集成的模块。
这里则分别定义了核心框架和自定义框架:

...
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);
}
...

上述代码中,会分别添加核心库CoreModulesPackage和自定义库packages,并且根据需要添加DebugCore库。
然后会在createReactContext()函数中对这些库进行注册。

createReactContext()

这里开始就会开启React的Application,进入到mCreateReactContextThread线程中的createReactContext()函数。
首先会将上述的核心库CroeModulesPackage与自定义库packages合并的mPackages通过processPackages()函数进行注册。保存在NativeModuleRegistryBuilder类中的Map集合中。
同时会创建ReactApplicationContext,其内部会封装Application ContextCatalystInstance对象和RN框架的三大线程。
其中在createReactContext()函数中调用了runJSBundle()来加载JS层代码。该代码就在CatalysInstance类中。
而后的setupReactContext()函数则会在js层代码准备完毕后,完成Native页面渲染,调用attachRootViewToInstance()函数来完成。

...
mCreateReactContextThread = new Thread(null, new Runnable() {
@Override
public void run() {

final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
...
Runnable setupReactContextRunnable = new Runnable() {
@Override
public void run() {
try {
setupReactContext(reactApplicationContext);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
};
}
}, "create_react_context");
ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
mCreateReactContextThread.start();

以下为createReactContext函数内容:

private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());
// 创建ReactApplicationContext
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

// 开启debug模式里异常处理器
NativeModuleCallExceptionHandler exceptionHandler =
mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);

// 创建JavaModule注册表
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);

// 创建CatalystInstanceImpl中的builder
CatalystInstanceImpl.Builder catalystInstanceBuilder =
new CatalystInstanceImpl.Builder()
// 包含了创建的消息队列和配置信息
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
// JS执行器
.setJSExecutor(jsExecutor)
// java module注册表
.setRegistry(nativeModuleRegistry)
// JSBundle加载器
.setJSBundleLoader(jsBundleLoader)
// JavaException 处理器
.setNativeModuleCallExceptionHandler(exceptionHandler);

// 构建对象
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}

// 关联ReactApplicationContext
reactContext.initializeWithInstance(catalystInstance);

// 开启加载执行JS Bundle
catalystInstance.runJSBundle();

return reactContext;
}

其中两个重要参数:JavaScriptExecutorJSBundleLoader

  • JavaScriptExecutor:该类加载时,会自动加载reactnativejnifb.so库,并且会调用Native层的initHybrid()函数,用来初始化C++层RN与JSC通信的框架。
  • JSBundleLoader:缓存了JSBundle对象,不同的场景会创建不同的Loader。封装了加载JSBundle的相关接口loadScript()

总结

1.Activity开启时调用onCreate()生命周期函数。
2.调用ReactActivityDelegateonCreate()函数,并调用内部的loadApp()函数,并在内部调用startReactApplication()函数。
3.这个过程首先会通过getReactInstanceManager()函数创建我们需要的核心框架CoreModulesPackage以及自定义部分框架,并准备CatalystInstance的builder参数。
4.至ReactRootView中的createReactContextInBackground()函数调用至runCreateReactContextOnNewThread函数中线程的createReactContext()函数。内部则会完成创建ReactApplicationContext对象并且绑定CatalystInstance、三大线程以及Application Context
5.调用CatalystInstance对象中的runJSBundle()函数,完成JSBundle加载,,这里也完成了大部分功能的加载:构建JS环境等功能。
6.最后调用setupReactContext()函数加载页面,通过attachRootViewToInstance()函数调用的runApplication()来完成。

github

二、CatalystInstance

CatalystInstance

CatalystInstance为接口,他的实现类为CatalystInstanceImpl。以下为其构造函数。

private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl");

mHybridData = initHybrid();

// 创建三大线程,内部包括,UI线程,Native线程,JS线程
mReactQueueConfiguration =
ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec, new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;

// JS Module注册表。
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "initializeCxxBridge");
// 调用native接口创建通信桥
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
}

上面重要的一部分就是ReactQueueConfiguration对象创建。ReactQueueConfiguation为接口,实现类为ReactQueueConfiguationImpl
public interface ReactQueueConfiguration {
MessageQueueThread getUIQueueThread();
MessageQueueThread getNativeModulesQueueThread();
MessageQueueThread getJSQueueThread();
void destroy();
}

接口定义如上,其中的三个线程分别为UI线程,Native线程与JS线程。

UI线程:完成Android的UI线程及其相关工作。
Native线程:完成通信工作。
JS线程:完成JS的执行与渲染工作。

runJSBundle

继续runJSBundle()函数调用。

首先需要看下上面的createReactContext函数。

 //创建CatalystInstanceImpl的Builder,它是三端通信的管理类
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
//JS执行器
.setJSExecutor(jsExecutor)
//Java Module注册表
.setRegistry(nativeModuleRegistry)
//JS Bundle加载器
.setJSBundleLoader(jsBundleLoader)
//Java Exception处理器
.setNativeModuleCallExceptionHandler(exceptionHandler);

代码跳跃可以知道,JSBundleLoader类用于创建本身对象,参数的类型为JSBundleLoaderDelegate。而这里传进去的参数为CatalystInstanceImpl环境本身,因为CatalystInstanceImpl的实现接口有JSBundleLoaderDelegate
public static JSBundleLoader createFileLoader(
final String fileName, final String assetUrl, final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
return fileName;
}
};
}

实现的函数就在CatalystInstanceImpl类中。
@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
}

CatalystInstanceImpl.cpp

jni函数调用的位置就是CatalystInstanceImpl.cpp的JNI层。

void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
[&fileName, &script]() {
script = JSBigFileString::fromPath(fileName);
});
instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
}
}

之后到Instance.cpp中:
void Instance::loadRAMBundleFromFile(const std::string& sourcePath, const std::string& sourceURL, bool loadSynchronously) {
auto bundle = folly::make_unique<JSIndexedRAMBundle>(sourcePath.c_str());
auto startupScript = bundle->getStartupCode();
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(bundle), JSIndexedRAMBundle::buildFactory());
loadRAMBundle(
std::move(registry),
std::move(startupScript),
sourceURL,
loadSynchronously);
}

void Instance::loadRAMBundle(std::unique_ptr<RAMBundleRegistry> bundleRegistry, std::unique_ptr<const JSBigString> startupScript, std::string startupScriptSourceURL, bool loadSynchronously) {
if (loadSynchronously) {
loadApplicationSync(std::move(bundleRegistry), std::move(startupScript),
std::move(startupScriptSourceURL));
} else {
loadApplication(std::move(bundleRegistry), std::move(startupScript),
std::move(startupScriptSourceURL));
}
}

void Instance::loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
std::unique_ptr<const JSBigString> string,
std::string sourceURL) {
callback_->incrementPendingJSCalls();
SystraceSection s("Instance::loadApplication", "sourceURL",
sourceURL);
nativeToJsBridge_->loadApplication(std::move(bundleRegistry), std::move(string),
std::move(sourceURL));
}

最后可以看到最终调用的是jnc层的loadApplication函数,并最后通过JSExecutor来与JS进行通信。

上述有点绕
整体调用如下,从runJSBundle()开始:

1.调用至CatalystInstanceImpl中并调用JSBundleLoader类中的JSBundleLoaderDelegate()函数,但是该函数的实现确实在CatalystInstanceImpl类中。
2.通过CatalystInstanceImpl中实现的JSBundleLoaderDelegate()函数,我们进入了JNI层CatalystinstanceImpl.cpp文件,并调用至jniLoadScriptFromFile进入JNI层。
3.最后调用至NativeToJsBridge.cpp,看名字就知道,这个是从Native层进入JS层的重要类。这个类中的loadApplicationScript()函数进入JSExecutor类,这个类真正连接了JS层。
4.找到MessageQueue.js类,这里就是上面native层进入js层的通信类。调用flushedQueue()函数。完成整体的启动过程。

github

C++ 与 JS 中间层

上面注意调用的flush()函数完成通信至MessageQueue.js
其中,这样的通信函数共有四个(MessageQueue.js中):

callFunctionReturnFlushedQueue()
invokeCallbackAndReturnFlushedQueue()
flushedQueue()
callFunctionReturnResultAndFlushedQueue()

完成这个的注册是由JSIExecutor中的bindBridge()函数完成,会从__fbBatchedBridge对象中取出的上面四个函数。
他们分别存在C++层中一下四个参数:

callFunctionReturnFlushedQueue_
invokeCallbackAndReturnFlushedQueue_
flushedQueue_
callFunctionReturnResultAndFlushedQueue_

这样使得C++可以调用这四个函数,贯穿通信。

void JSIExecutor::bindBridge() {
std::call_once(bindFlag_, [this] {
SystraceSection s("JSIExecutor::bindBridge (once)");
Value batchedBridgeValue =
runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) {
throw JSINativeException(
"Could not get BatchedBridge, make sure your bundle is packaged correctly");
}

Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
*runtime_, "callFunctionReturnFlushedQueue");
invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
*runtime_, "invokeCallbackAndReturnFlushedQueue");
flushedQueue_ =
batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
callFunctionReturnResultAndFlushedQueue_ =
batchedBridge.getPropertyAsFunction(
*runtime_, "callFunctionReturnResultAndFlushedQueue");
});
}

这里开始就是进入MessageQueue.js运行代码。

三、ReactRootView

上面的过程从ReactActivity开始一直运行到MessageQueue.js,过程中的createReactContext()函数为分界点。之后就是调用setupReactContext()函数。


private void setupReactContext(final ReactApplicationContext reactContext) {
...
synchronized (mAttachedReactRoots) {
...

// NativeModule初始化
catalystInstance.initialize();
// 绑定ReactContext
mDevSupportManager.onNewReactContextCreated(reactContext);
// 注册内存压力通知
mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
moveReactContextToCurrentLifecycleState();

ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
// 将ReactRootView与CatalystInstance绑定
for (ReactRoot reactRoot : mAttachedReactRoots) {
attachRootViewToInstance(reactRoot);
}
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
}
...
}


private void attachRootViewToInstance(final ReactRoot reactRoot) {
UIManager uiManager = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());

@Nullable Bundle initialProperties = reactRoot.getAppProperties();
// 将ReactRootView作为根布局
final int rootTag = uiManager.addRootView(reactRoot.getRootViewGroup(), initialProperties == null ? new WritableNativeMap() : Arguments.fromBundle(initialProperties), reactRoot.getInitialUITemplate());
reactRoot.setRootViewTag(rootTag);
...

if (reactRoot.getUIManagerType() == FABRIC) {
// Fabric requires to call updateRootLayoutSpecs before starting JS Application,
// this ensures the root will hace the correct pointScaleFactor.
uiManager.updateRootLayoutSpecs(
rootTag, reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec());
reactRoot.setShouldLogContentAppeared(true);
} else {
reactRoot.runApplication();
}
}

这里定义最重要的页面工作,将ReactRootView作为根布局,并且会执行runApplication()来进入JS层页面。

@Override
public void runApplication() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
try {
if (mUseSurface) {
// TODO call surface's runApplication
} else {
if (mWasMeasured) {
updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec);
}
WritableNativeMap appParams = new WritableNativeMap();
appParams.putDouble("rootTag", getRootViewTag());
@Nullable Bundle appProperties = getAppProperties();
if (appProperties != null) {
appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
}
mShouldLogContentAppeared = true;
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
}
}
}

这里展示的部分代码,调用AppRegistry.js内部的runApplication()函数来完成JS层页面的渲染。
最终转换成Native层UI现实在手机上。

四、AppRegistry.js