转载

从 Hello World 看 RN 的启动流程(二)

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 方法,方法 initHybridgetJSCallInvokerHolder 都是 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.cpploadScriptFromString 方法的实现:

// 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
      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 方法的声明。

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;
// ...

BridgeCallbackCatalystInstanceImpl 类的一个私有类,继续顺着调用链往下走:

BridgeCallback#onBatchComplete --> NativeModuleRegistry#onBatchComplete 找到 UIManager 接口模块 
--> UIManagerModule#onBatchComplete --> UIImplementation#dispatchViewUpdates

UIManagerModule 类是 UIManager 接口的实现,其主要作用是桥接 JS 层去创建和更新 Native views,而 UIImplementation 类的主要作用将 JS 层的 React node 转为 Shadow node,便于后续和 Native views 作映射。从而,现有架构下的渲染原理如下图所示:

从 Hello World 看 RN 的启动流程(二)

而 Fabric 架构出来之后,就没有 UIManager 模块了,取而代之的是 FabricUIManager ,并将 Shadow 层从 Java 层移到了 C++ 层,这也是 Fabric 能提升 RN 性能的一个原因所在。

<本文完>

参考

  • React Native Android 源码框架浅析
  • 庖丁解牛!深入剖析 React Native 下一代架构重构
原文  https://github.com/dwqs/blog/issues/76
正文到此结束
Loading...