前文
提到了 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
方法的参数说明如下:
从这可以看出,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); // ... } // ...
在 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
方法。
但它的子类是谁呢?
回到 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 SoLoader.loadLibrary("jscexecutor"); return new JSCExecutorFactory(appName, deviceName); } catch (UnsatisfiedLinkError jscE) { // Otherwise use 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
方法的声明。
找到了 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代码中看看后续的流程。
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(); } // ... } // ...
继续看 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 性能的一个原因所在。
<本文完>