从 Hello World 看 RN 的启动流程(二)
dwqs opened this issue · 1 comments
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 性能的一个原因所在。
<本文完>
参考
第一次知道居然有人拿github的issue当做博客, 这真是amazing啊 ^. ^