We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前文提到了 CatalystInstance 是一个接口类型,但其继承了 JSBundleLoaderDelegate 接口,后者定义了不同的 js bundle 加载方法声明:
CatalystInstance
JSBundleLoaderDelegate
// 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 的构造方法:
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 方法的参数说明如下:
initializeBridge
从这可以看出,js 和 Java 之间并不直接通信,而是以 C++ 作为中间层。
除了 initializeBridge 方法,方法 initHybrid 和 getJSCallInvokerHolder 都是 Native C++ 方法,我们先看下 CatalystInstanceImpl.cpp 注册的方法:
initHybrid
getJSCallInvokerHolder
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:
runJSBundle
// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java // ... public void runJSBundle() { // ... mJSBundleLoader.loadScript(CatalystInstanceImpl.this); // ... } // ...
在 runJSBundle 方法中,实际上会去调用 JSBundleLoader 实例的 loadScript 方法。
JSBundleLoader
loadScript
在前文初始化 ReactInstanceManager 实例时,提到了 JSBundleLoader 实例化。对于不同的场景,会有不同的 JSBundleLoader 实例化方式,而在创建 ReactInstanceManager 实例时,默认的实现是 JSBundleLoader#createAssetLoader:
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 方法:
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 中,具体看其实现:
jniLoadScriptFromAssets
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 方法的实现:
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 方法:
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 的实现:
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 方法:
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.h
但它的子类是谁呢?
回到 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 实例:
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 实例:
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 中查看调用链:
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 的声明:
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 中。
delegate_
ExecutorDelegate
但类 ExecutorDelegate 是一个虚拟类,方法 callNativeModules 是一个虚拟方法(可类比 Java 中的抽象类和抽象方法来理解),因而这里实际调用的是其子类的对应方法:
callNativeModules
// 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 是哪来的?
m_callback
我们回想一下调用链路,在创建 CatalystInstance 实例的时候,同时会调用 C++ 层的 CatalystInstanceImpl::initializeBridge 方法,传入的第一个实数就是 BridgeCallback 实例,对应 C++ 层方法中第一个形参 callback。而在 CatalystInstanceImpl::initializeBridge 方法中又会调用 Instance::initializeBridge 方法,同时将 callback 作为一个参数透传,在 Instance::initializeBridge 方法中又会初始化 NativeToJsBridge 实例,同时将包装后的 callback 作为最后一个参数透传,在类 NativeToJsBridge 的构造函数中会初始化 JsToNativeBridge,将 callback 透传。
CatalystInstanceImpl::initializeBridge
BridgeCallback
callback
Instance::initializeBridge
NativeToJsBridge
JsToNativeBridge
至此,js bundle 加载和解析流程完成了,我们回到Java代码中看看后续的流程。
createReactContext 方法返回之后,继续往后执行:
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 方法:
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 实例。
mAttachedReactRoots
ReactInstanceManager#attachRootView
attachRootView
ReactRootView#attachToReactInstanceManager
ReactRootView
继续看 attachRootViewToInstance 方法的实现:
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 方法的实现:
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 的调用就会有一个统一的入口:
AppRegistry
AppRegistry.class
// 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 方法实现的。
CatalystInstance#callFunction
CatalystInstanceImpl::jniCallJSFunction
AppRegistry 类的具体实现在 AppRegistry.js 中:
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 组件对应呢?
run
renderApplication
上文说到了,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 作映射。从而,现有架构下的渲染原理如下图所示:
UIManagerModule
UIManager
UIImplementation
而 Fabric 架构出来之后,就没有 UIManager 模块了,取而代之的是 FabricUIManager,并将 Shadow 层从 Java 层移到了 C++ 层,这也是 Fabric 能提升 RN 性能的一个原因所在。
FabricUIManager
<本文完>
The text was updated successfully, but these errors were encountered:
第一次知道居然有人拿github的issue当做博客, 这真是amazing啊 ^. ^
Sorry, something went wrong.
No branches or pull requests
CatalystInstanceImpl
前文提到了
CatalystInstance
是一个接口类型,但其继承了JSBundleLoaderDelegate
接口,后者定义了不同的 js bundle 加载方法声明:我们首先来看下类
CatalystInstance
的子类CatalystInstanceImpl
的构造方法:initializeBridge
方法的参数说明如下:从这可以看出,js 和 Java 之间并不直接通信,而是以 C++ 作为中间层。
除了
initializeBridge
方法,方法initHybrid
和getJSCallInvokerHolder
都是 Native C++ 方法,我们先看下CatalystInstanceImpl.cpp
注册的方法:然后简单看下方法
initializeBridge
的 C++ 实现:到此,类
CatalystInstanceImpl
的实例初始化就完成了,同时通过initializeBridge
方法建立了 Bridge 连接(Java <--> C++ <--> JS )。在实例初始化后,就调用了实例的runJSBundle
方法开始加载 js bundle:JSBundleLoader
在
runJSBundle
方法中,实际上会去调用JSBundleLoader
实例的loadScript
方法。在前文初始化
ReactInstanceManager
实例时,提到了JSBundleLoader
实例化。对于不同的场景,会有不同的JSBundleLoader
实例化方式,而在创建ReactInstanceManager
实例时,默认的实现是JSBundleLoader#createAssetLoader
:可以看到它会继续调用
CatalystInstanceImpl
实例中的loadScriptFromAssets
方法:上文已经提到了
jniLoadScriptFromAssets
方法的注册是在CatalystInstanceImpl.cpp
中,具体看其实现:继续看
Instance.cpp
中loadScriptFromString
方法的实现:在
loadScriptFromString
方法中,根据是否异步调用不同的方法。根据上文分析,loadSynchronously
的值是false
,所以会继续调用loadApplication
方法:继续看
NativeToJsBridge::loadApplication
的实现:到这里,离终点就差一步了。这差的一步就是
JSExecutor
类并没有实现loadApplicationScript
方法:但头文件
JSExecutor.h
中却包含了loadApplicationScript
的声明,这说明是由类JSExecutor
的子类实现了loadApplicationScript
方法。但它的子类是谁呢?
寻找 JSExecutor 的子类
回到 Java 中最初创建 js 执行器工厂实例的地方:
getDefaultJSExecutorFactory
方法会先去加载jscexecutor
库,然后返回一个JSCExecutorFactory
实例:jscexecutor
库加载完成之后,会去注册 C++ 方法initHybrid
:顺着 Java 的调用链继续往下走,来到前文提到的创建 ReactContext 的地方:
上文提到了
JSCExecutorFactory
类实现了接口JavaScriptExecutorFactory
,同时从上文可以看到create
方法返回的是JSCExecutor
实例:继续回到上文的
OnLoad.cpp
中查看调用链:从上述代码可以看到,
initHybrid
方法最终返回了JSIExecutor
实例。继续往下看头文件JSIExecutor.h
的声明:至此,我们找到了类
JSExecutor
的子类JSIExecutor
,并看到其头文件中对loadApplicationScript
方法的声明。JSIExecutor.cpp
找到了
loadApplicationScript
方法的声明,那就可以看其具体的实现了:在
JSIExecutor
的构造函数声明中可以看到,delegate_
是类ExecutorDelegate
的实例,其声明是在头文件JSExecutor.h
中。但类
ExecutorDelegate
是一个虚拟类,方法callNativeModules
是一个虚拟方法(可类比 Java 中的抽象类和抽象方法来理解),因而这里实际调用的是其子类的对应方法:看到这里,你可能想知道
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
方法返回之后,继续往后执行:当线程任务
setupReactContextRunnable
启动之后,会去调用setupReactContext
方法:先简单追溯一下
mAttachedReactRoots
被赋值的链路:mAttachedReactRoots
是在ReactInstanceManager#attachRootView
方法中被赋值,attachRootView
方法是在ReactRootView#attachToReactInstanceManager
方法中被调用,参数是ReactRootView
实例,所以mAttachedReactRoots
中保存的都是ReactRootView
实例。继续看
attachRootViewToInstance
方法的实现:回到 ReactRootView
继续看
runApplication
方法的实现:AppRegistry
类是 js 层暴露给 Java 层 JS module,所有的 JS module 都是接口,不能直接调用。但通过代理对象(AppRegistry.class
),Java 对 JS 的调用就会有一个统一的入口:从上述代码可知,所有 Java 对 JS 的调用都是通过
CatalystInstance#callFunction
方法实现,但最终都是通过 C++ 中的CatalystInstanceImpl::jniCallJSFunction
方法实现的。AppRegistry
类的具体实现在AppRegistry.js
中:run
方法会去调用renderApplication
方法去渲染 JS 组件,那 js 组件怎么和 Native 组件对应呢?上文说到了,js bundle 执行之后会回调 Java:
类
BridgeCallback
是CatalystInstanceImpl
类的一个私有类,继续顺着调用链往下走:UIManagerModule
类是UIManager
接口的实现,其主要作用是桥接 JS 层去创建和更新 Native views,而UIImplementation
类的主要作用将 JS 层的 React node 转为 Shadow node,便于后续和 Native views 作映射。从而,现有架构下的渲染原理如下图所示:而 Fabric 架构出来之后,就没有
UIManager
模块了,取而代之的是FabricUIManager
,并将 Shadow 层从 Java 层移到了 C++ 层,这也是 Fabric 能提升 RN 性能的一个原因所在。<本文完>
参考
The text was updated successfully, but these errors were encountered: