-
Notifications
You must be signed in to change notification settings - Fork 443
Description
CatalystInstanceImpl
前文提到了 CatalystInstance 是一个接口类型,但其继承了 JSBundleLoaderDelegate 接口,后者定义了不同的 js bundle 加载方法声明:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java
// ...
public interface JSBundleLoaderDelegate {
// 从 Android assets 加载 bundle
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
// 从文件系统加载 bundle,用于自定义 bundle 加载路径
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
// 从 Metro 中加载增量 bundle
void loadScriptFromDeltaBundle(
String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously);
void setSourceURLs(String deviceURL, String remoteURL);
}我们首先来看下类 CatalystInstance 的子类 CatalystInstanceImpl 的构造方法:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
// ...
public class CatalystInstanceImpl implements CatalystInstance {
// ...
// C++ 层
private final HybridData mHybridData;
private static native HybridData initHybrid();
public native JSCallInvokerHolderImpl getJSCallInvokerHolder();
private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
// 略去日志输出代码
// C++ 方法,用来创建JNI(Java Native Interface)相关状态
mHybridData = initHybrid();
// 初始化线程配置(即上文提到的 Native Modules、js以及UI线程)
mReactQueueConfiguration =
ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec, new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
// 略去日志输出代码
// C++方法,用来初始化Bridge,并创建BridgeCallback实例
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
// ...
}
// ...
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,
MessageQueueThread jsQueue,
MessageQueueThread moduleQueue,
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
// ...
public CatalystInstanceImpl build() {
return new CatalystInstanceImpl(
Assertions.assertNotNull(mReactQueueConfigurationSpec),
Assertions.assertNotNull(mJSExecutor),
Assertions.assertNotNull(mRegistry),
Assertions.assertNotNull(mJSBundleLoader),
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
}
}
// ...initializeBridge 方法的参数说明如下:
- callback: CatalystInstanceImpl 的静态内部类 BridgeCallback 实例 ,负责接口回调
- jsExecutor: js 执行器实例,将 js 的调用传递给 C++ 层
- jsQueue:js 线程
- moduleQueue: Native Modules 线程
- javaModules: Java Modules
- cxxModules: C++ Modules
从这可以看出,js 和 Java 之间并不直接通信,而是以 C++ 作为中间层。
除了 initializeBridge 方法,方法 initHybrid 和 getJSCallInvokerHolder 都是 Native C++ 方法,我们先看下 CatalystInstanceImpl.cpp 注册的方法:
// react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
// ...
void CatalystInstanceImpl::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid),
makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge),
// ...
// 后文会提到 jniLoadScriptFromAssets 方法
makeNativeMethod("jniLoadScriptFromAssets", CatalystInstanceImpl::jniLoadScriptFromAssets),
// ...
makeNativeMethod("jniExtendNativeModules", CatalystInstanceImpl::getJSCallInvokerHolder),
// ...
});
JNativeRunnable::registerNatives();
}
// ...然后简单看下方法 initializeBridge 的 C++ 实现:
// react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
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> nativeModulesQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
// TODO mhorowitz: how to assert here?
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
moduleMessageQueue_ = std::make_shared<JMessageQueueThread>(nativeModulesQueue);
moduleRegistry_ = std::make_shared<ModuleRegistry>(
buildNativeModuleList(
std::weak_ptr<Instance>(instance_),
javaModules,
cxxModules,
moduleMessageQueue_));
/**
* instance_ 是类 Instance 的实例
* Instance.cpp 位于 react-native/ReactCommon/cxxreact 目录
* 后文还会提到这个
*/
instance_->initializeBridge(
std::make_unique<JInstanceCallback>(
callback,
moduleMessageQueue_),
jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(jsQueue),
moduleRegistry_);
}到此,类 CatalystInstanceImpl 的实例初始化就完成了,同时通过 initializeBridge 方法建立了 Bridge 连接(Java <--> C++ <--> JS )。在实例初始化后,就调用了实例的 runJSBundle 方法开始加载 js bundle:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
// ...
public void runJSBundle() {
// ...
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
// ...
}
// ...JSBundleLoader
在 runJSBundle 方法中,实际上会去调用 JSBundleLoader 实例的 loadScript 方法。
在前文初始化 ReactInstanceManager 实例时,提到了 JSBundleLoader 实例化。对于不同的场景,会有不同的 JSBundleLoader 实例化方式,而在创建 ReactInstanceManager 实例时,默认的实现是 JSBundleLoader#createAssetLoader:
// react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
// ...
return new ReactInstanceManager(
mApplication,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
? getDefaultJSExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
// ...
);
// ...
// react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
// ...
public abstract class JSBundleLoader {
// ...
public static JSBundleLoader createAssetLoader(
final Context context, final String assetUrl, final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
}
// ...
}
// ...可以看到它会继续调用 CatalystInstanceImpl 实例中的 loadScriptFromAssets 方法:
//...
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
}
// ...
// C++ 方法
private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
// ...上文已经提到了 jniLoadScriptFromAssets 方法的注册是在 CatalystInstanceImpl.cpp 中,具体看其实现:
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
// 获取 js Bundle 的路径名,一般默认值是 index.android.bundle
auto sourceURL = assetURL.substr(kAssetsLength);
/**
* 调用 JSLoader.cpp 中的 extractAssetManager 方法提取 AssetManager
* 返回值来自于系统动态链接库 android/asset_manager_jni.h的AAssetManager_fromJava方法
*/
auto manager = extractAssetManager(assetManager);
// 调用JSLoader.cpp的loadScriptFromAssets()方法读取JS Bundle里的内容
auto script = loadScriptFromAssets(manager, sourceURL);
/**
* 是否是unbundle命令打包
* RN Android 打包用了 react.gradle 的默认bundle,没用unbundle命令
*/
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)) {
// 是否是 RAMBundle ???
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
} else {
// 调用类 Instance 实例的 loadScriptFromString 方法
instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
}
}继续看 Instance.cpp 中 loadScriptFromString 方法的实现:
// react-native/ReactCommon/cxxreact/Instance.cpp
/**
* string为index.android.bundle内容
* sourceURL 默认是 index.android.bundle
*/
void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,
std::string sourceURL,
bool loadSynchronously) {
SystraceSection s("Instance::loadScriptFromString", "sourceURL",
sourceURL);
if (loadSynchronously) {
loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));
} else {
loadApplication(nullptr, std::move(string), std::move(sourceURL));
}
}在 loadScriptFromString 方法中,根据是否异步调用不同的方法。根据上文分析,loadSynchronously 的值是 false,所以会继续调用 loadApplication 方法:
// react-native/ReactCommon/cxxreact/Instance.cpp
void Instance::loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
std::unique_ptr<const JSBigString> string,
std::string sourceURL) {
/**
* callback_ 是在 Java 中调用 initializeBridge 传进来的,其实现是
CatalystInstanceImpl的BridgeCallback
* 这里调用回调应该是告诉 Java 端要加载 bundle 了
*/
callback_->incrementPendingJSCalls();
SystraceSection s("Instance::loadApplication", "sourceURL",
sourceURL);
/**
* nativeToJsBridge_ 是类 NativeToJsBridge.cpp 的实例
* 是在 Instance::initializeBridge方法里初始化的
*/
nativeToJsBridge_->loadApplication(std::move(bundleRegistry), std::move(string),
std::move(sourceURL));
}继续看 NativeToJsBridge::loadApplication 的实现:
// react-native/ReactCommon/cxxreact/NativeToJsBridge.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 {
/**
* 进一步调用 JSExecutor::loadApplicationScript 方法,
* 调用到这里时,才真正去加载 js bundle,并解析 js
* startupScript 是 bundle 字符串
* startupScriptSourceURL 是 bundle url
*/
executor->loadApplicationScript(std::move(*startupScript),
std::move(startupScriptSourceURL));
} catch (...) {
m_applicationScriptHasFailure = true;
throw;
}
});
}
// 到这里,离终点就差一步了。这差的一步就是 JSExecutor 类并没有实现 loadApplicationScript 方法:
// react-native/ReactCommon/cxxreact/JSExecutor.cpp
#include "JSExecutor.h"
#include "RAMBundleRegistry.h"
#include <folly/Conv.h>
namespace facebook {
namespace react {
std::string JSExecutor::getSyntheticBundlePath(
uint32_t bundleId,
const std::string& bundlePath) {
if (bundleId == RAMBundleRegistry::MAIN_BUNDLE_ID) {
return bundlePath;
}
return folly::to<std::string>("seg-", bundleId, ".js");
}
}
}但头文件 JSExecutor.h 中却包含了 loadApplicationScript 的声明,这说明是由类 JSExecutor 的子类实现了 loadApplicationScript 方法。
但它的子类是谁呢?
寻找 JSExecutor 的子类
回到 Java 中最初创建 js 执行器工厂实例的地方:
// react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java
// ...
return new ReactInstanceManager(
mApplication,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
? getDefaultJSExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
// ...
);
private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName) {
try {
// 加载 C++ 层的 jscexecutor,优先考虑使用 JSC 引擎
SoLoader.loadLibrary("jscexecutor");
return new JSCExecutorFactory(appName, deviceName);
} catch (UnsatisfiedLinkError jscE) {
// JSC 加载失败,就使用 Hermes 引擎
return new HermesExecutorFactory();
}
}getDefaultJSExecutorFactory 方法会先去加载 jscexecutor 库,然后返回一个 JSCExecutorFactory 实例:
// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutorFactory.java
// 实现接口 JavaScriptExecutorFactory
public class JSCExecutorFactory implements JavaScriptExecutorFactory {
private final String mAppName;
private final String mDeviceName;
public JSCExecutorFactory(String appName, String deviceName) {
this.mAppName = appName;
this.mDeviceName = deviceName;
}
@Override
public JavaScriptExecutor create() throws Exception {
WritableNativeMap jscConfig = new WritableNativeMap();
jscConfig.putString("OwnerIdentity", "ReactNative");
jscConfig.putString("AppIdentity", mAppName);
jscConfig.putString("DeviceIdentity", mDeviceName);
return new JSCExecutor(jscConfig);
}
// ...
}jscexecutor 库加载完成之后,会去注册 C++ 方法 initHybrid:
// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp
// ...
class JSCExecutorHolder
: public jni::HybridClass<JSCExecutorHolder, JavaScriptExecutorHolder> {
public:
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/jscexecutor/JSCExecutor;";
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ReadableNativeMap *) {
// ...
// TODO mhorowitz T28461666 fill in some missing nice to have glue
return makeCxxInstance(folly::make_unique<JSCExecutorFactory>());
}
// 注册 initHybrid 方法供 Java 端调用
static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
});
}
// ...
};
// ...
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return facebook::jni::initialize(
vm, [] { facebook::react::JSCExecutorHolder::registerNatives(); });
}顺着 Java 的调用链继续往下走,来到前文提到的创建 ReactContext 的地方:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private class ReactContextInitParams {
private final JavaScriptExecutorFactory mJsExecutorFactory;
private final JSBundleLoader mJsBundleLoader;
public ReactContextInitParams(
JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
mJsExecutorFactory = Assertions.assertNotNull(jsExecutorFactory);
mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader);
}
public JavaScriptExecutorFactory getJsExecutorFactory() {
return mJsExecutorFactory;
}
public JSBundleLoader getJsBundleLoader() {
return mJsBundleLoader;
}
}
// ...
private void recreateReactContextInBackground(
JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
// ...
final ReactContextInitParams initParams =
new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
// ...
runCreateReactContextOnNewThread(initParams);
// ...
}
// ...
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
// ...
// 创建 ReactContext
final ReactApplicationContext reactApplicationContext =
createReactContext(
// 返回 JavaScriptExecutorFactory 实例并且调用 create 方法
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
mCreateReactContextThread = null;
// ...
}
// ...上文提到了 JSCExecutorFactory 类实现了接口 JavaScriptExecutorFactory,同时从上文可以看到 create 方法返回的是 JSCExecutor 实例:
// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutor.java
// ...
// 实现抽象类 JavaScriptExecutor
@DoNotStrip
class JSCExecutor extends JavaScriptExecutor {
// ...
JSCExecutor(ReadableNativeMap jscConfig) {
/**
* 调用父类的构造函数,参数是 C++ 方法 initHybrid 的返回值
* 上文已经说过,jscexecutor 库加载完成之后,就会注册 initHybrid 方法供 Java 端调用
* JavaScriptExecutor 类的构造函数中仅仅是保存该返回值
*/
super(initHybrid(jscConfig));
}
@Override
public String getName() {
return "JSCExecutor";
}
private static native HybridData initHybrid(ReadableNativeMap jscConfig);
}继续回到上文的 OnLoad.cpp 中查看调用链:
// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp
// ...
#include <jsireact/JSIExecutor.h>
// ...
// 继承 JSExecutorFactory 类
class JSCExecutorFactory : public JSExecutorFactory {
public:
std::unique_ptr<JSExecutor> createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) override {
auto installBindings = [](jsi::Runtime &runtime) {
react::Logger androidLogger =
static_cast<void (*)(const std::string &, unsigned int)>(
&reactAndroidLoggingHook);
react::bindNativeLogger(runtime, androidLogger);
};
return folly::make_unique<JSIExecutor>(
jsc::makeJSCRuntime(),
delegate,
JSIExecutor::defaultTimeoutInvoker,
installBindings);
}
};
// ...
class JSCExecutorHolder
// ...
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ReadableNativeMap *) {
// ...
return makeCxxInstance(folly::make_unique<JSCExecutorFactory>());
}
// ...从上述代码可以看到,initHybrid 方法最终返回了 JSIExecutor 实例。继续往下看头文件 JSIExecutor.h 的声明:
// react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h
// ...
class JSIExecutor : public JSExecutor {
public:
using RuntimeInstaller = std::function<void(jsi::Runtime &runtime)>;
// 构造函数声明
JSIExecutor(
std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ExecutorDelegate> delegate,
const JSIScopedTimeoutInvoker &timeoutInvoker,
RuntimeInstaller runtimeInstaller);
void loadApplicationScript(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
// ...
}
// ...至此,我们找到了类 JSExecutor 的子类 JSIExecutor,并看到其头文件中对 loadApplicationScript 方法的声明。
JSIExecutor.cpp
找到了 loadApplicationScript 方法的声明,那就可以看其具体的实现了:
// react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp
// ...
/**
* script: bundle 内容(字符串)
* sourceURL: bundle 地址
*/
void JSIExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) {
// 略去一些全局设置和 debug 下的代码
if (runtimeInstaller_) {
runtimeInstaller_(*runtime_);
}
// 略去日志输出代码
// 关键代码:使用 webkit JSC 去真正解释执行Javascript了
runtime_->evaluateJavaScript(
std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
flush();
// 略去日志输出代码
}
// ...
void JSIExecutor::flush() {
SystraceSection s("JSIExecutor::flush");
// flushedQueue_ 还没被赋值,继续往下走
if (flushedQueue_) {
callNativeModules(flushedQueue_->call(*runtime_), true);
return;
}
/**
* BatchedBridge.enqueueNativeCall 方法是否被调用过(如果 js 调用过 Java 模块,该方法也会被调用),如果被调用过,
* 会在 global 对象上定义一个 __fbBatchedBridge 属性,其值是 BatchedBridge
* BatchedBridge 是 MessageQueue 的一个实例,
* 具体见:react-native/Libraries/BatchedBridge/BatchedBridge.js
*/
Value batchedBridge =
runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
if (!batchedBridge.isUndefined()) {
// 还没被调用过
// 调用 bindBridge 方法绑定 js bridge,见下文
bindBridge();
callNativeModules(flushedQueue_->call(*runtime_), true);
} else if (delegate_) {
callNativeModules(nullptr, true);
}
}
// ...
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_ 进行赋值
* 通过webkit JSC 获取 MessageQueue.js 的 flushedQueue 属性值(函数)
*/
flushedQueue_ =
batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
callFunctionReturnResultAndFlushedQueue_ =
batchedBridge.getPropertyAsFunction(
*runtime_, "callFunctionReturnResultAndFlushedQueue");
});
}
void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) {
SystraceSection s("JSIExecutor::callNativeModules");
// If this fails, you need to pass a fully functional delegate with a
// module registry to the factory/ctor.
CHECK(delegate_) << "Attempting to use native modules without a delegate";
#if 0
// 将函数 flushedQueue_ 的返回值 json 化
std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
.getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
.getString(*runtime_).utf8(*runtime_);
#endif
// 调用 delegate_ 的 callNativeModules 方法
delegate_->callNativeModules(
*this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}
// ...在 JSIExecutor 的构造函数声明中可以看到,delegate_ 是类 ExecutorDelegate 的实例,其声明是在头文件 JSExecutor.h 中。
但类 ExecutorDelegate 是一个虚拟类,方法 callNativeModules 是一个虚拟方法(可类比 Java 中的抽象类和抽象方法来理解),因而这里实际调用的是其子类的对应方法:
// react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp
// ...
class JsToNativeBridge : public react::ExecutorDelegate {
public:
// 构造函数
JsToNativeBridge(std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<InstanceCallback> callback)
: m_registry(registry)
, m_callback(callback) {}
// 重写父类的 callNativeModules
void callNativeModules(
__unused JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
CHECK(m_registry || calls.empty()) <<
"native module calls cannot be completed with no native modules";
m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();
for (auto& call : parseMethodCalls(std::move(calls))) {
// 调用 Native Registry 表中的java NativeMethod方法。
m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
// isEndOfBatch 的值是 true
if (isEndOfBatch) {
// onBatchComplete will be called on the native (module) queue, but
// decrementPendingJSCalls will be called sync. Be aware that the bridge may still
// be processing native calls when the bridge idle signaler fires.
if (m_batchHadNativeModuleCalls) {
/**
* 回调 Java 端,通知 Java 端 js bundle 已经加载完成
* m_callback 是 Java 类 BridgeCallback 的实例
*/
m_callback->onBatchComplete();
m_batchHadNativeModuleCalls = false;
}
m_callback->decrementPendingJSCalls();
}
}
// ...看到这里,你可能想知道 m_callback 是哪来的?
我们回想一下调用链路,在创建 CatalystInstance 实例的时候,同时会调用 C++ 层的 CatalystInstanceImpl::initializeBridge 方法,传入的第一个实数就是 BridgeCallback 实例,对应 C++ 层方法中第一个形参 callback。而在 CatalystInstanceImpl::initializeBridge 方法中又会调用 Instance::initializeBridge 方法,同时将 callback 作为一个参数透传,在 Instance::initializeBridge 方法中又会初始化 NativeToJsBridge 实例,同时将包装后的 callback 作为最后一个参数透传,在类 NativeToJsBridge 的构造函数中会初始化 JsToNativeBridge,将 callback 透传。
至此,js bundle 加载和解析流程完成了,我们回到Java代码中看看后续的流程。
回到 ReactInstanceManager
createReactContext 方法返回之后,继续往后执行:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
// ...
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
mCreateReactContextThread = null;
// ...
Runnable setupReactContextRunnable =
new Runnable() {
@Override
public void run() {
try {
setupReactContext(reactApplicationContext);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
};
reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
// ...
}当线程任务 setupReactContextRunnable 启动之后,会去调用 setupReactContext 方法:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private void setupReactContext(final ReactApplicationContext reactContext) {
// ...
synchronized (mAttachedReactRoots) {
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
// 初始化 Native Modules
catalystInstance.initialize();
// ...
// 遍历 mAttachedReactRoots
for (ReactRoot reactRoot : mAttachedReactRoots) {
attachRootViewToInstance(reactRoot);
}
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
}
// ...
}
// ...先简单追溯一下 mAttachedReactRoots 被赋值的链路:mAttachedReactRoots 是在 ReactInstanceManager#attachRootView 方法中被赋值,attachRootView 方法是在 ReactRootView#attachToReactInstanceManager 方法中被调用,参数是 ReactRootView 实例,所以 mAttachedReactRoots 中保存的都是 ReactRootView 实例。
继续看 attachRootViewToInstance 方法的实现:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
// ...
private void attachRootViewToInstance(final ReactRoot reactRoot) {
// ...
// 将ReactRootView作为根布局
UIManager uiManager =
UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());
// 获取初始化参数
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
// 获取 rootTag
final int rootTag =
uiManager.addRootView(
reactRoot.getRootViewGroup(),
initialProperties == null
? new WritableNativeMap()
: Arguments.fromBundle(initialProperties),
reactRoot.getInitialUITemplate());
// 设置 RootView 的 rootTag
reactRoot.setRootViewTag(rootTag);
// RootView 的类型判断,默认类型是 DEFAULT
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 {
// 调用 runApplication 方法
reactRoot.runApplication();
}
// ...
}
// ...回到 ReactRootView
继续看 runApplication 方法的实现:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
// ...
import com.facebook.react.modules.appregistry.AppRegistry;
// ...
public void runApplication() {
// ...
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
return;
}
CatalystInstance catalystInstance = reactContext.getCatalystInstance();
/**
* 获取 module name
* 这个 module name 就是在 js 端调用 registerComponent 的第一个参数
*/
String jsAppModuleName = getJSModuleName();
if (mUseSurface) {
// TODO call surface's runApplication
} else {
if (mWasMeasured) {
updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec);
}
// 包装 RN 应用启动时的初始化参数
WritableNativeMap appParams = new WritableNativeMap();
appParams.putDouble("rootTag", getRootViewTag());
@Nullable Bundle appProperties = getAppProperties();
if (appProperties != null) {
appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
}
mShouldLogContentAppeared = true;
// 启动 RN 应用的入口
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
}
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
// ...AppRegistry 类是 js 层暴露给 Java 层 JS module,所有的 JS module 都是接口,不能直接调用。但通过代理对象(AppRegistry.class),Java 对 JS 的调用就会有一个统一的入口:
// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
// ...
@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;
}
// ... 从上述代码可知,所有 Java 对 JS 的调用都是通过 CatalystInstance#callFunction 方法实现,但最终都是通过 C++ 中的 CatalystInstanceImpl::jniCallJSFunction 方法实现的。
AppRegistry 类的具体实现在 AppRegistry.js 中:
// ...
registerComponent(
appKey: string,
componentProvider: ComponentProvider,
section?: boolean,
): string {
runnables[appKey] = {
componentProvider,
/**
* appParameters 是原生端初始化 RN 应用时透传的参数
* 属性主要包含用于初始化的 initialProps,rootTag,fabric等
*/
run: appParameters => {
renderApplication(
// ...
)
},
};
// ...
return appKey;
},
// ...
runApplication(appKey: string, appParameters: any): void {
// ...
runnables[appKey].run(appParameters);
},
// ...run 方法会去调用 renderApplication 方法去渲染 JS 组件,那 js 组件怎么和 Native 组件对应呢?
上文说到了,js bundle 执行之后会回调 Java:
// ...
/**
* 回调 Java 端,通知 Java 端 js bundle 已经加载完成
* m_callback 是 Java 类 BridgeCallback 的实例
*/
m_callback->onBatchComplete();
m_batchHadNativeModuleCalls = false;
// ...类 BridgeCallback 是 CatalystInstanceImpl 类的一个私有类,继续顺着调用链往下走:
BridgeCallback#onBatchComplete --> NativeModuleRegistry#onBatchComplete 找到 UIManager 接口模块
--> UIManagerModule#onBatchComplete --> UIImplementation#dispatchViewUpdates
UIManagerModule 类是 UIManager 接口的实现,其主要作用是桥接 JS 层去创建和更新 Native views,而 UIImplementation 类的主要作用将 JS 层的 React node 转为 Shadow node,便于后续和 Native views 作映射。从而,现有架构下的渲染原理如下图所示:
而 Fabric 架构出来之后,就没有 UIManager 模块了,取而代之的是 FabricUIManager,并将 Shadow 层从 Java 层移到了 C++ 层,这也是 Fabric 能提升 RN 性能的一个原因所在。
<本文完>
