接着上篇我们继续分析setupReactContext方法
arduino
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
setupReactContext(reactApplicationContext);
}
setupReactContext函数核心方法
- catalystInstance.initialize:初始化
- attachRootViewToInstance->reactRoot.runApplication:启动RN应用
- ReactContext初始化完成监听回调,开发者可以监听这个事件做相关开发
scss
private void setupReactContext(final ReactApplicationContext reactContext) {
synchronized (mAttachedReactRoots) {
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
catalystInstance.initialize();
...
for (ReactRoot reactRoot : mAttachedReactRoots) {
attachRootViewToInstance(reactRoot);
}
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
}
...
com.facebook.react.ReactInstanceEventListener[] listeners =
new com.facebook.react.ReactInstanceEventListener[mReactInstanceEventListeners.size()];
final com.facebook.react.ReactInstanceEventListener[] finalListeners =
mReactInstanceEventListeners.toArray(listeners);
UiThreadUtil.runOnUiThread(
() -> {
moveReactContextToCurrentLifecycleState();
for (com.facebook.react.ReactInstanceEventListener listener : finalListeners) {
// Sometimes this listener is null - probably due to race
// condition between allocating listeners with a certain
// size, and getting a `final` version of the array on
// the following line.
if (listener != null) {
listener.onReactContextInitialized(reactContext);
}
}
});
}
在NativeModules线程上调用每一个NativeModule的initialize方法
typescript
public void initialize() {
mInitialized = true;
mNativeModulesQueueThread.runOnQueue(
() -> {
mNativeModuleRegistry.notifyJSInstanceInitialized();
});
}
private void doInitialize(NativeModule module) {
...
if (shouldInitialize) {
module.initialize();
// Once finished, set flags accordingly, but we don't expect anyone to wait for this to
// finish
// So no need to notify other threads
synchronized (this) {
mIsInitializing = false;
}
}
...
}
attachRootViewToInstance方法中会启动RN应用
scss
private void attachRootViewToInstance(final ReactRoot reactRoot) {
...
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
final int rootTag;
if (reactRoot.getUIManagerType() == FABRIC) {
rootTag =
uiManager.startSurface(
reactRoot.getRootViewGroup(),
reactRoot.getJSModuleName(),
initialProperties == null
? new WritableNativeMap()
: Arguments.fromBundle(initialProperties),
reactRoot.getWidthMeasureSpec(),
reactRoot.getHeightMeasureSpec());
reactRoot.setShouldLogContentAppeared(true);
} else {
rootTag =
uiManager.addRootView(
reactRoot.getRootViewGroup(),
initialProperties == null
? new WritableNativeMap()
: Arguments.fromBundle(initialProperties));
reactRoot.setRootViewTag(rootTag);
reactRoot.runApplication();
}
...
}
我们这里看不是FABRIC,它是新架构的 渲染器和组件,因此我们看reactRoot.runApplication
- 启动时可以传入启动参数
- 调用getJSModule
- mJSModuleRegistry:JavaScriptModuleRegistry对象
java
public void runApplication() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication" );
try {
...
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);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
@Override
public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
}
JavaScriptModuleRegistry核心能力:Java层调用JS中指定的module中方法,这里的意图是希望调用JS中的AppRegistry.runApplication(appParams),但是Java层是无法直接调用JS,所以这里会有一个黑科技
java
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
CatalystInstance instance, Class<T> moduleInterface) {
JavaScriptModule module = mModuleInstances.get(moduleInterface);
if (module != null) {
return (T) module;
}
JavaScriptModule interfaceProxy =
(JavaScriptModule)
Proxy.newProxyInstance(
moduleInterface.getClassLoader(),
new Class[] {moduleInterface},
new JavaScriptModuleInvocationHandler(instance, moduleInterface));
mModuleInstances.put(moduleInterface, interfaceProxy);
return (T) interfaceProxy;
}
getJSModule返回的是JavaScriptModule的动态代理,当执行runApplication调用时,会触发执行JavaScriptModuleInvocationHandler.invoke
- getJSModuleName:返回字符串"AppRegistry"
- method.getName:返回字符串"runApplication"
- jsArgs:调用runApplication方法所需参数
less
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
return null;
}
所以JavaScriptModuleRegistry的作用就是将
scss
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
转化为
arduino
mCatalystInstance.callFunction("AppRegistry", "runApplication", jsArgs);
mCatalystInstance.callFunction最终会调用到C++层CatalystInstanceImpl对应的jniCallJSFunction方法,由C++实现JS模块的调用
arduino
private native void jniCallJSFunction(String module, String method, NativeArray arguments);
//jniCallJSFunction进一步调用
instance_->callJSFunction(std::move(module), std::move(method), arguments->consume());
//callJSFunction调用
nativeToJsBridge_->callFunction(std::move(module), std::move(method), std::move(params));
executor是JSIExecutor对象,会调用到JSIExecutor.callFunction
typescript
void NativeToJsBridge::callFunction(
std::string&& module,
std::string&& method,
folly::dynamic&& arguments) {
...
executor->callFunction(module, method, arguments);
});
}
callFunction主要完成 3 件事:
- bindBridge:绑定JS中的全局函数,这样C++就可以调用JS了
- callFunctionReturnFlushedQueue_->call:调用JS中指定模块和方法
- callNativeModules:JS执行会返回Native 调用队列,然后调用callNativeModules执行Native调用
c
void JSIExecutor::callFunction(
const std::string& moduleId,
const std::string& methodId,
const folly::dynamic& arguments) {
SystraceSection s(
"JSIExecutor::callFunction" , "moduleId" , moduleId, "methodId" , methodId);
if (!callFunctionReturnFlushedQueue_) {
bindBridge();
}
auto errorProducer = [=] {
std::stringstream ss;
ss << "moduleID: " << moduleId << " methodID: " << methodId;
return ss.str();
};
Value ret = Value::undefined();
try {
scopedTimeoutInvoker_(
[&] {
ret = callFunctionReturnFlushedQueue_->call(
*runtime_,
moduleId,
methodId,
valueFromDynamic(*runtime_, arguments));
},
std::move(errorProducer));
} catch (...) {
std::throw_with_nested(
std::runtime_error( "Error calling " + moduleId + "." + methodId));
}
callNativeModules(ret, true);
}
如果是第一次调用会调用bindBridge
- 通过runtime_查找到JS中的全局变量 __fbBatchedBridge
- 然后获取到JS中如下三个方法,有了这3 个方法就能实现C++调用JS了
ini
void JSIExecutor::bindBridge() {
std::call_once(bindFlag_, [this] {
SystraceSection s( "JSIExecutor::bindBridge (once)" );
Value batchedBridgeValue =
runtime_->global().getProperty(*runtime_, "__fbBatchedBridge" );
if (batchedBridgeValue.isUndefined() || !batchedBridgeValue.isObject()) {
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" );
});
}
__fbBatchedBridge位于BatchedBridge.js文件中,可以看到它其实就是MessageQueue对象
ini
const MessageQueue = require( './MessageQueue' );
const BatchedBridge: MessageQueue = new MessageQueue();
Object.defineProperty(global, '__fbBatchedBridge' , {
configurable: true,
value: BatchedBridge,
});
module.exports = BatchedBridge;
MessageQueue对象中这三个方法的核心模式一致:被C++层调用,在 JS 侧执行某些操作后,把执行期间产生的 Native 调用队列批量返回给 C++ 侧处理 ,形成了 Native → JS(其中可能会调用Native API) → Native 的完整调用闭环
| 方法 | JS 签名 | 触发场景 | JS 侧执行 | 返回值 | C++ 对返回值的处理 |
|---|---|---|---|---|---|
| callFunctionReturnFlushedQueue | (module, method, args) | Native 调用 JS 模块方法 | __callFunction(module, method, args) | 积压的 Native 调用队列 | callNativeModules(ret, true) |
| invokeCallbackAndReturnFlushedQueue | (cbID, args) | Native 触发 JS 回调(如 Promise resolve/reject) | __invokeCallback(cbID, args) | 积压的 Native 调用队列 | callNativeModules(ret, true) |
| flushedQueue | () | 无需执行 JS 函数,仅刷新积压队列 | __callReactNativeMicrotasks() | 积压的 Native 调用队列 或 null | callNativeModules(ret, true) |
继续回到,这里我们执行的moduleId="AppRegistry",methodId="runApplication"
ini
ret = callFunctionReturnFlushedQueue_->call(
*runtime_,
moduleId,
methodId,
valueFromDynamic(*runtime_, arguments));
}
callFunctionReturnFlushedQueue会调用到__callFunction(module, method, args)
php
__callFunction(module: string, method: string, args: mixed[]): void {
try {
//查找模块
const moduleMethods = this.getCallableModule(module);
...
//调用模块对应方法
moduleMethods[method].apply(moduleMethods, args);
} finally {
Systrace.endEvent();
}
}
AppRegistry模块位于AppRegistry.js,它里面有runApplication的实现,看到这里我们就不继续分析,核心流程基本分析完成。
这里有个有意思的问题callFunctionReturnFlushedQueue_为什么返回Native调用队列?然后又为什么调用callNativeModules?这是因为旧架构的原因:在旧架构(Bridge 模式)下,JS 通过队列调 Native 都是异步的,所有调用是被放到_queue队列中
scss
JS 调用 NativeModule.method(args)
→ enqueueNativeCall() 存入 _queue
→ 等下次 Native 来取(或 nativeFlushQueueImmediate 主动触发)
→ Native 执行完通过 invokeCallback 回调 JS
❌ JS 无法同步拿到返回值
队列方式下,JS 无法主动通知 Native 来取队列,只能等 Native 下次调用 JS 时,把积压的队列"捎带"回去。
css
t1: Native 调用 JS → callFunctionReturnFlushedQueue("AppRegistry", "runApplication", args)
│
├── JS 执行 runApplication
│ ├── 内部调了 UIManager.createView(...) → 存入 _queue
│ ├── 内部调了 UIManager.setChildren(...) → 存入 _queue
│ └── 内部调了 AsyncStorage.setItem(...) → 存入 _queue
│
└── JS 执行完毕,调用 flushedQueue()
├── 取出 _queue
├── 清空 _queue
└── return queue ←── 捎带给 Native
t2: C++ 拿到返回的 queue → callNativeModules(queue) → 逐一执行 Native 调用
返回队列不是"还有任务没做完",而是队列方式下 JS → Native 的唯一传回通道 --- JS 把调用信息打包,借着 Native 调 JS 的机会"顺路"带回去。这也是为什么三个方法都以 ReturnFlushedQueue 或 flushedQueue 结尾 --- 每一次 Native → JS 的调用都是一次捎带的机会。
arduino
void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
...
delegate_->callNativeModules(
*this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}
- delegate_是JsToNativeBridge对象
- nativeModules_:JSINativeModules对象,里面包含ModuleRegistry对象
- moduleRegistry_:ModuleRegistry对象
arduino
void callNativeModules(
[[maybe_unused]] JSExecutor& executor,
folly::dynamic&& calls,
bool isEndOfBatch) override {
...
for (auto& call : methodCalls) {
m_registry->callNativeMethod(
call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
...
}
callNativeModules中最终会调用到Java层对应的NativeMethod,这里我们不分析了,后面我们会详细分析Java与JS的通信。