启动流程
RN的页面也是依托Activity,React Native框架里有一个ReactActivity
,它就是我们RN页面的容器。
ReactActivity里有个ReactRootView
,正如它的名字那样,它就是 ReactActivity的root View,最终渲染出来的view都会添加到这个ReactRootView上。
ReactRootView调用自己的startReactApplication()
方法启动了整个RN页面,在启动的过程中先去创建页面上下文ReactContext
,然后再去加载、执行并将JavaScript映射成Native Widget,最终一个RN页面就显示在了用户面前。
整个RN页面的启动流程图如下所示
启动流程图
- 创建
ReactRootView
过程
public class MainActivity extends ReactActivity {}
public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private final ReactActivityDelegate mDelegate;
protected ReactActivity() {
mDelegate = createReactActivityDelegate();
}
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName());
}
}
public class ReactActivityDelegate {
public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
}
protected void onCreate(Bundle savedInstanceState) {
if (mMainComponentName != null) {
loadApp(mMainComponentName);
}
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}
protected void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
appKey,
getLaunchOptions());
getPlainActivity().setContentView(mReactRootView);
}
}
- 创建
ReactInstanceManager
public ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceManager == null) {
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
mReactInstanceManager = createReactInstanceManager();
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
}
return mReactInstanceManager;
}
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
// 应用上下文
.setApplication(mApplication)
//JSMainModuleP相当于应用首页的js Bundle,可以传递url从服务器拉取js Bundle
//当然这个只在dev模式下可以使用
.setJSMainModulePath(getJSMainModuleName())
//是否开启dev模式
.setUseDeveloperSupport(getUseDeveloperSupport())
//红盒的回调
.setRedBoxHandler(getRedBoxHandler())
//JS执行器
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
//自定义UI实现机制,这个我们一般用不到
.setUIImplementationProvider(getUIImplementationProvider())
.setJSIModulesPackage(getJSIModulePackage())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
//添加我们外面设置的Package
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();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
}
- 创建
ReactContext
ReactContext
我们看到从最初的startReactApplication
最终会调用到这里
public class ReactInstanceManager {
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor,
JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
//ReactApplicationContext是ReactContext的包装类。
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
//debug模式里开启异常处理器,就是我们开发中见到的调试工具(红色错误框等)
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
//创建JavaModule注册表
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
//创建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);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
// CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
final CatalystInstance catalystInstance;
//构建CatalystInstance实例
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
if (mBridgeIdleDebugListener != null) {
catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
}
if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
//开启加载执行JS Bundle
catalystInstance.runJSBundle();
//关联catalystInstance与reactContext
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
}
在这个方法里完成了RN页面上下文ReactContext的创建,我们先来看看这个方法的两个入参:
-
jsExecutor
:JSCJavaScriptExecutor
继承于JavaScriptExecutor
,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用Native方法initHybrid()
初始化C++层RN与JSC通信的框架。 -
jsBundleLoader
:缓存了JSBundle的信息,封装了上层加载JSBundle的相关接口,CatalystInstanceImpl
实现了JSBundleLoaderDelegate
接口,可以间接调用ReactBridge
的 native 方法去加载JS文件,不同的场景会创建不同的加载器,具体可以查看类JSBundleLoader。
可以看到在ReactContext创建的过程中,主要做了以下几件事情:
- 构建
ReactApplicationContext
对象,ReactApplicationContext是ReactContext的包装类。 - 利用
jsExecutor
、nativeModuleRegistry
、jsBundleLoader
、exceptionHandler
等参数构建CatalystInstance
实例,作为以为三端通信的中枢。 - 调用
CatalystInstance.runJSBundle()
开始加载执行JS。
另一个重要的角色CatalystInstance出现了,前面我们也说过它是三端通信的中枢。关于通信的具体实现我们会在接下来的通信机制小节来讲述,我们先来接着看JS的加载过程。
加载 JS Bundle
首先是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注册表实例,这个在以前的代码版本中是在上面的createReactContext()方法中创建的
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");
//在C++层初始化通信桥
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());
}
ReactQueueConfigurationSpec
用来创建ReactQueueConfiguration
的实例,ReactQueueConfiguration
同样是个接口,它的实现类是ReactQueueConfigurationImpl
。ReactQueueConfiguration
的定义如下
public interface ReactQueueConfiguration {
//UI线程
MessageQueueThread getUIQueueThread();
//Native线程
MessageQueueThread getNativeModulesQueueThread();
//JS线程
MessageQueueThread getJSQueueThread();
void destroy();
}
JS Bundle的加载实际上是指C++层完成的,我们看一下序列图
JSBundle 有三种加载方式:
setSourceURLs
, loadScriptFromAssets
, loadScriptFromFile
而真正执行JS的地方是 JSCExector.cpp 的
loadApplicationScript()
方法
void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) {
SystraceSection s("JSCExecutor::loadApplicationScript",
"sourceURL", sourceURL);
...
switch (jsStatus) {
case JSLoadSourceIsCompiled:
if (!bcSourceCode) {
throw std::runtime_error("Unexpected error opening compiled bundle");
}
//调用JavaScriptCore里的方法验证JS是否有效,并解释执行
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
flush();
ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
return;
case JSLoadSourceErrorVersionMismatch:
throw RecoverableError(explainLoadSourceStatus(jsStatus));
case JSLoadSourceErrorOnRead:
case JSLoadSourceIsNotCompiled:
// Not bytecode, fall through.
break;
}
}
void JSCExecutor::flush() {
SystraceSection s("JSCExecutor::flush");
if (m_flushedQueueJS) {
//调用MessageQueue.js的flushedQueue()方法
callNativeModules(m_flushedQueueJS->callAsFunction({}));
return;
}
// When a native module is called from JS, BatchedBridge.enqueueNativeCall()
// is invoked. For that to work, require('BatchedBridge') has to be called,
// and when that happens, __fbBatchedBridge is set as a side effect.
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
// So here, if __fbBatchedBridge doesn't exist, then we know no native calls
// have happened, and we were able to determine this without forcing
// BatchedBridge to be loaded as a side effect.
if (!batchedBridgeValue.isUndefined()) {
// If calls were made, we bind to the JS bridge methods, and use them to
// get the pending queue of native calls.
bindBridge();
callNativeModules(m_flushedQueueJS->callAsFunction({}));
} else if (m_delegate) {
// If we have a delegate, we need to call it; we pass a null list to
// callNativeModules, since we know there are no native calls, without
// calling into JS again. If no calls were made and there's no delegate,
// nothing happens, which is correct.
callNativeModules(Value::makeNull(m_context));
}
}
可以看到这个方法主要是调用JavaScriptCore里的evaluateSourceCode()
方法验证JS是否有效,并解释执行。然后再调用flush()
方法调用JS层里的方法执行JS Bundle。
上面提到flush()
方法调用MessageQueue.js的flushedQueue()
方法,这是如何做到的呢?
事实上这是由bindBridge()
方法来完成的,它从__fbBatchedBridge
对象中取出MessageQueue.js里的四个方法
callFunctionReturnFlushedQueue()
invokeCallbackAndReturnFlushedQueue()
flushedQueue()
callFunctionReturnResultAndFlushedQueue()
并分别存在四个C++变量中:
m_callFunctionReturnFlushedQueueJS
m_invokeCallbackAndReturnFlushedQueueJS
m_flushedQueueJS
m_callFunctionReturnResultAndFlushedQueueJS
这样C++就可以调用这四个JS方法。
void JSCExecutor::bindBridge() throw(JSException) {
SystraceSection s("JSCExecutor::bindBridge");
std::call_once(m_bindFlag, [this] {
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) {
auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge");
if (!requireBatchedBridge.isUndefined()) {
batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
}
if (batchedBridgeValue.isUndefined()) {
throw JSException("Could not get BatchedBridge, make sure your bundle is packaged correctly");
}
}
auto batchedBridge = batchedBridgeValue.asObject();
m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
});
}
绑定ReactContext与ReactRootView
JS Bundle加载完成以后,前面说的createReactContext()
就执行完成了,然后开始执行setupReacContext()
方法,绑定ReactContext
与ReactRootView
。 我们来看一下它的实现。
public class ReactInstanceManager {
private void setupReactContext(final ReactApplicationContext reactContext) {
//...
//执行Java Module的初始化
catalystInstance.initialize();
//通知ReactContext已经被创建爱女
mDevSupportManager.onNewReactContextCreated(reactContext);
//内存状态回调设置
mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
//复位生命周期
moveReactContextToCurrentLifecycleState();
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) {
//将所有的ReactRootView与catalystInstance进行绑定
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView, catalystInstance);
}
}
//...
}
private void attachRootViewToInstance(
final ReactRootView rootView,
CatalystInstance catalystInstance) {
//...
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
//将ReactRootView作为根布局
final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag);
//执行JS的入口bundle页面
rootView.invokeJSEntryPoint();
//...
}
}
JS的页面入口我们可以设置mJSEntryPoint
来自定义入口,如果不设置则是默认的入口AppRegistry。
private void defaultJSEntryPoint() {
//...
try {
//...
String jsAppModuleName = getJSModuleName();
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
这里的调用方式实际上就是原生调用JS的方法,它调用的正是我们很熟悉的AppRegistry.js,AppRegistry.js调用runApplication()开始执行JS页面的渲染,最终转换为Native UI显示在手机上。
到此为止,整个RN页面的启动流程就分析完了,我们接着来看看RN页面是如何渲染最终显示在手机上的。
渲染
RN页面的入口一般是AppRegistry.js,先看一下RN页面的渲染流程序列图,如下所示:
整体渲染过程
大体过程:
- React Native将代码由JSX转化为JS组件,启动过程中利用
instantiateReactComponent
将ReactElement
转化为复合组件ReactCompositeComponent
与元组件ReactNativeBaseComponent
,利用ReactReconciler
对他们进行渲染。 - UIManager.js利用C++层的Instance.cpp将UI信息传递给UIManagerModule.java,并利用UIManagerModule.java构建UI。
- UIManagerModule.java接收到UI信息后,将UI的操作封装成对应的Action,放在队列中等待执行。各种UI的操作,例如创建、销毁、更新等便在队列里完成,UI最终得以渲染在屏幕上。
JavaScript层组件渲染
JavaScript层组件渲染-
AppRegistry.registerComponent
用来注册组件,在该方法内它会调用AppRegistry.runApplication()
来启动js的渲染流程。 -
AppRegistry.runApplication()
会将传入的Component转换成ReactElement,并在外面包裹一层AppContaniner,AppContaniner主要用来提供一些debug工具(例如:红盒)
// ReactNativeMount.js
renderComponent: function(
nextElement: ReactElement<*>,
containerTag: number,
callback?: ?(() => void)
): ?ReactComponent<any, any, any> {
//将RectElement使用相同的TopLevelWrapper进行包裹
var nextWrappedElement = React.createElement(
TopLevelWrapper,
{ child: nextElement }
);
var topRootNodeID = containerTag;
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props.child;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement, emptyObject);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
}
return prevComponent;
} else {
ReactNativeMount.unmountComponentAtNode(containerTag);
}
}
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return null;
}
ReactNativeTagHandles.assertRootTag(containerTag);
//检查之前的节点是否已经mount到目标节点上,如果有则进行比较处理
var instance = instantiateReactComponent(nextWrappedElement, false);
ReactNativeMount._instancesByContainerID[containerTag] = instance;
// The initial render is synchronous but any updates that happen during
// rendering, in componentWillMount or componentDidMount, will be batched
// according to the current batching strategy.
//将mount任务提交给回调Queue,最终会调用ReactReconciler.mountComponent()
ReactUpdates.batchedUpdates(
batchedMountComponentIntoNode,
instance,
containerTag
);
var component = instance.getPublicInstance();
if (callback) {
callback.call(component);
}
return component;
},
该方法主要做了以下事情:
- 将传入的
RectElement
使用相同的TopLevelWrapper进行包裹,生成nextWrappedElement
。 - 检查之前的节点是否已经mount到目标节点上,如果有则进行比较处理,将上一步生成的
nextWrappedElement
传入instantiateReactComponent(nextWrappedElement, false)
方法。 - 将mount任务提交给回调Queue,最终会调用
ReactReconciler.mountComponent()
,ReactReconciler.mountComponent()又会去调用C++层Instance::mountComponent()
方法。
React组件可以分为两种:
- 元组件:框架内置的,可以直接使用的组件。例如:View、Image等。它在React Native中用
ReactNativeBaseComponent
来描述。 - 复合组件:用户封装的组件,一般可以通过
React.createClass()
来构建,提供render()
方法来返回渲染目标。它在React Native中用ReactCompositeComponent来描述。
instantiateReactComponent(node, shouldHaveDebugID)
方法就是根据对象的type生成元组件或者复合组件。
function instantiateReactComponent(node, shouldHaveDebugID) {
var instance;
if (node === null || node === false) {
instance = ReactEmptyComponent.create(instantiateReactComponent);
} else if (typeof node === 'object') {
var element = node;
var type = element.type;
if (typeof type !== 'function' && typeof type !== 'string') {
var info = '';
if (process.env.NODE_ENV !== 'production') {
if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
info += ' You likely forgot to export your component from the file ' + 'it\'s defined in.';
}
}
info += getDeclarationErrorAddendum(element._owner);
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info) : _prodInvariant('130', type == null ? type : typeof type, info) : void 0;
}
//如果对象的type为string,则调用ReactHostComponent.createInternalComponent(element)来注入生成组件的逻辑
if (typeof element.type === 'string') {
instance = ReactHostComponent.createInternalComponent(element);
}
//如果是内部元组件,则创建一个type实例
else if (isInternalComponentType(element.type)) {
// This is temporarily available for custom components that are not string
// representations. I.e. ART. Once those are updated to use the string
// representation, we can drop this code path.
instance = new element.type(element);
// We renamed this. Allow the old name for compat. :(
if (!instance.getHostNode) {
instance.getHostNode = instance.getNativeNode;
}
}
//否则,则是用户创建的复合组件,这个时候创建一个ReactCompositeComponentWrapper实例,该实例用来描述复合组件
else {
instance = new ReactCompositeComponentWrapper(element);
}
//当对象为string或者number时,调用ReactHostComponent.createInstanceForText(node)来注入组件生成逻辑。
} else if (typeof node === 'string' || typeof node === 'number') {
instance = ReactHostComponent.createInstanceForText(node);
} else {
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : _prodInvariant('131', typeof node) : void 0;
}
if (process.env.NODE_ENV !== 'production') {
process.env.NODE_ENV !== 'production' ? warning(typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.getHostNode === 'function' && typeof instance.unmountComponent === 'function', 'Only React Components can be mounted.') : void 0;
}
// These two fields are used by the DOM and ART diffing algorithms
// respectively. Instead of using expandos on components, we should be
// storing the state needed by the diffing algorithms elsewhere.
instance._mountIndex = 0;
instance._mountImage = null;
if (process.env.NODE_ENV !== 'production') {
instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0;
}
// Internal instances should fully constructed at this point, so they should
// not get any new fields added to them at this point.
if (process.env.NODE_ENV !== 'production') {
if (Object.preventExtensions) {
Object.preventExtensions(instance);
}
}
return instance;
}
该方法根据对象的type生成元组件或者复合组件,具体流程如下:
- 如果对象的type为string,则调用
ReactHostComponent.createInternalComponent(element)
来注入生成组件的逻辑,如果是内部元组件,则创建一个type实例, - 否则,则是用户创建的复合组件,这个时候创建一个
ReactCompositeComponentWrapper
实例,该实例用来描述复合组件。 - 当对象为string或者number时,调用
ReactHostComponent.createInstanceForText(node)
来注入组件生成逻辑。 - 以上都不是,则报错。
我们可以看到,UI渲染主要通过UIManager来完成,UIManager是一个ReactModule,UIManager.js里的操作都会对应到UIManagerModule里来。我们接着来看看Java层的渲染流程
Java层的渲染流程
Java 层渲染Java层的组件渲染分为以下几步:
- JS层通过C++层把创建View的请求发送给Java层的UIManagerModule。
- UIManagerModule通过UIImplentation对操作请求进行包装。
- 包装后的操作请求被发送到View处理队列UIViewOperationQueue队列中等待处理。
- 实际处理View时,根据class name查询对应的ViewNManager,然后调用原生View的方法对View进行相应的操作。
通信机制
Java层与JavaScript层的相互调用都不是直接完成的,而是间接通过C++层来完成的。在介绍通信机制之前我们先来理解一些基本的概念。
JavaScript Module注册表
说起JavaScript Module注册表,我们需要先理解几个类/接口:
-
JavaScriptModule
:这是一个接口,JS Module都会继承此接口,它表示在JS层会有一个相同名字的js文件,该js文件实现了该接口定义的方法,JavaScriptModuleRegistry会利用动态代理将这个接口生成代理类,并通过C++传递给JS层,进而调用JS层的方法。 -
JavaScriptModuleRegistration
用来描述JavaScriptModule的相关信息,它利用反射获取接口里定义的Method。 -
JavaScriptModuleRegistry
:JS Module注册表,内部维护了一个HashMap:HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations,JavaScriptModuleRegistry利用动态代理生成接口JavaScriptModule对应的代理类,再通过C++传递到JS层,从而调用JS层的方法。
Java Module注册表
要理解Java Module注册表,我们同样也需要理解3个类/接口:
-
NativeModule
:是一个接口,实现了该接口则可以被JS层调用,我们在为JS层提供Java API时通常会继承BaseJavaModule/ReactContextBaseJavaModule,这两个类就实现了NativeModule接口。 -
ModuleHolder
:NativeModule的一个Holder类,可以实现NativeModule的懒加载。 -
NativeModuleRegistry
:Java Module注册表,内部持有Map:Map<Class<? extends NativeModule>, ModuleHolder> mModules,NativeModuleRegistry可以遍历并返回Java Module供调用者使用。
其中 NativeModuleRegistry是在createReactContext()
方法里构建的。
JavaScriptModuleRegistry是在CatalystInstanceImpl
的构建方法里构建的.
这些都是在CatalystInstanceImpl的构建方法里通过native方法initializeBridge()传入了C++层,如下所示:
void CatalystInstanceImpl::initializeBridge(
jni::alias_ref<ReactCallback::javaobject> callback,
// This executor is actually a factory holder.
JavaScriptExecutorHolder* jseh,
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback),
jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(jsQueue),
folly::make_unique<JMessageQueueThread>(moduleQueue),
buildModuleRegistry(std::weak_ptr<Instance>(instance_),
javaModules, cxxModules));
}
-
callback
:CatalystInstanceImpl的静态内部类ReactCallback,负责接口回调。 -
jsExecutor
:JS执行器,将JS的调用传递给C++层。 -
jsQueue.getJSQueueThread()
:JS线程,通过mReactQueueConfiguration.getJSQueueThread()
获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()
创建。 -
moduleQueue
:Native线程,通过mReactQueueConfiguration.getNativeModulesQueueThread()
获得,mReactQueueConfiguration 通过ReactQueueConfigurationSpec.createDefault()
创建。 -
javaModules
:java modules,来源于mJavaRegistry.getJavaModules(this)
。它对应了C++层JavaModuleWrapper.cpp, JS在Java的时候最终会调用到这个类的inovke()
方法上。 -
cxxModules
:c++ modules,来源于mJavaRegistry.getCxxModules()
。ModuleHolder是NativeModule的一个Holder类,可以实现NativeModule的懒加载。
cxxModules
javaModules
这两个集合在CatalystInstanceImpl::initializeBridge()
被打包成ModuleRegistry传入Instance.cpp 中,并在NativeToJsBridge的构造方法中传给JsToNativeBridge,以后JS如果调用Java就可以通过 ModuleRegistry 来进行调用。
JNI作为C++与Java的桥梁,JSC作为C++与JavaScript的桥梁,而C++最终连接了Java与JavaScript。
RN通信结构 Java 调用 JS JS 调用 Java
网友评论