Skip to content
New issue

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

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

Open
dwqs opened this issue Aug 11, 2019 · 1 comment
Open

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

dwqs opened this issue Aug 11, 2019 · 1 comment

Comments

@dwqs
Copy link
Owner

dwqs commented Aug 11, 2019

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,优先考虑使用 JSC 引擎
      SoLoader.loadLibrary("jscexecutor");
      return new JSCExecutorFactory(appName, deviceName);
    } catch (UnsatisfiedLinkError jscE) {
      // JSC 加载失败,就使用 Hermes 引擎
      return new HermesExecutorFactory();
    }
  }

getDefaultJSExecutorFactory 方法会先去加载 jscexecutor 库,然后返回一个 JSCExecutorFactory 实例:

// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutorFactory.java

// 实现接口 JavaScriptExecutorFactory
public class JSCExecutorFactory implements JavaScriptExecutorFactory {
  private final String mAppName;
  private final String mDeviceName;

  public JSCExecutorFactory(String appName, String deviceName) {
    this.mAppName = appName;
    this.mDeviceName = deviceName;
  }

  @Override
  public JavaScriptExecutor create() throws Exception {
    WritableNativeMap jscConfig = new WritableNativeMap();
    jscConfig.putString("OwnerIdentity", "ReactNative");
    jscConfig.putString("AppIdentity", mAppName);
    jscConfig.putString("DeviceIdentity", mDeviceName);
    return new JSCExecutor(jscConfig);
  }

  // ...
}

jscexecutor 库加载完成之后,会去注册 C++ 方法 initHybrid

// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp

// ...

class JSCExecutorHolder
    : public jni::HybridClass<JSCExecutorHolder, JavaScriptExecutorHolder> {
 public:
  static constexpr auto kJavaDescriptor =
      "Lcom/facebook/react/jscexecutor/JSCExecutor;";

  static jni::local_ref<jhybriddata> initHybrid(
      jni::alias_ref<jclass>,
      ReadableNativeMap *) {
    // ...
    
    // TODO mhorowitz T28461666 fill in some missing nice to have glue
    return makeCxxInstance(folly::make_unique<JSCExecutorFactory>());
  }
  
  // 注册 initHybrid 方法供 Java 端调用    
  static void registerNatives() {
    registerHybrid({
        makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
    });
  }
 // ...
};

// ...

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
  return facebook::jni::initialize(
      vm, [] { facebook::react::JSCExecutorHolder::registerNatives(); });
}

顺着 Java 的调用链继续往下走,来到前文提到的创建 ReactContext 的地方:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...
 
  private class ReactContextInitParams {
    private final JavaScriptExecutorFactory mJsExecutorFactory;
    private final JSBundleLoader mJsBundleLoader;

    public ReactContextInitParams(
        JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
      mJsExecutorFactory = Assertions.assertNotNull(jsExecutorFactory);
      mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader);
    }

    public JavaScriptExecutorFactory getJsExecutorFactory() {
      return mJsExecutorFactory;
    }

    public JSBundleLoader getJsBundleLoader() {
      return mJsBundleLoader;
    }
  }
  
// ...

 private void recreateReactContextInBackground(
      JavaScriptExecutorFactory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
    
    // ...
    
    final ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    
    // ...

    runCreateReactContextOnNewThread(initParams);
    
    // ...
  }

// ...

  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
    // ...
    // 创建 ReactContext
    final ReactApplicationContext reactApplicationContext =
          createReactContext(
              // 返回 JavaScriptExecutorFactory 实例并且调用 create 方法
              initParams.getJsExecutorFactory().create(),
              initParams.getJsBundleLoader());

    mCreateReactContextThread = null;
    // ...
  }
// ...

上文提到了 JSCExecutorFactory 类实现了接口 JavaScriptExecutorFactory,同时从上文可以看到 create 方法返回的是 JSCExecutor 实例:

// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutor.java

// ...
// 实现抽象类 JavaScriptExecutor
@DoNotStrip
class JSCExecutor extends JavaScriptExecutor {
  // ...

  JSCExecutor(ReadableNativeMap jscConfig) {
    /** 
    * 调用父类的构造函数,参数是 C++ 方法 initHybrid 的返回值
    * 上文已经说过,jscexecutor 库加载完成之后,就会注册 initHybrid 方法供 Java 端调用
    * JavaScriptExecutor 类的构造函数中仅仅是保存该返回值
    */
    super(initHybrid(jscConfig));
  }

  @Override
  public String getName() {
    return "JSCExecutor";
  }

  private static native HybridData initHybrid(ReadableNativeMap jscConfig);
}

继续回到上文的 OnLoad.cpp 中查看调用链:

// react-native/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp

// ...

#include <jsireact/JSIExecutor.h>

// ...

// 继承 JSExecutorFactory 类
class JSCExecutorFactory : public JSExecutorFactory {
 public:
  std::unique_ptr<JSExecutor> createJSExecutor(
      std::shared_ptr<ExecutorDelegate> delegate,
      std::shared_ptr<MessageQueueThread> jsQueue) override {
    auto installBindings = [](jsi::Runtime &runtime) {
      react::Logger androidLogger =
          static_cast<void (*)(const std::string &, unsigned int)>(
              &reactAndroidLoggingHook);
      react::bindNativeLogger(runtime, androidLogger);
    };
    return folly::make_unique<JSIExecutor>(
        jsc::makeJSCRuntime(),
        delegate,
        JSIExecutor::defaultTimeoutInvoker,
        installBindings);
  }
};

// ...

class JSCExecutorHolder
  // ...
  
  static jni::local_ref<jhybriddata> initHybrid(
      jni::alias_ref<jclass>,
      ReadableNativeMap *) {
    // ...
    
    return makeCxxInstance(folly::make_unique<JSCExecutorFactory>());
  }
    
  // ...

从上述代码可以看到,initHybrid 方法最终返回了 JSIExecutor 实例。继续往下看头文件 JSIExecutor.h 的声明:

// react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h

// ...

class JSIExecutor : public JSExecutor {
  public:
    using RuntimeInstaller = std::function<void(jsi::Runtime &runtime)>;
  // 构造函数声明    
  JSIExecutor(
      std::shared_ptr<jsi::Runtime> runtime,
      std::shared_ptr<ExecutorDelegate> delegate,
      const JSIScopedTimeoutInvoker &timeoutInvoker,
      RuntimeInstaller runtimeInstaller);
  void loadApplicationScript(
      std::unique_ptr<const JSBigString> script,
      std::string sourceURL) override;
   
   // ...
}

// ...

至此,我们找到了类 JSExecutor 的子类 JSIExecutor,并看到其头文件中对 loadApplicationScript 方法的声明。

JSIExecutor.cpp

找到了 loadApplicationScript 方法的声明,那就可以看其具体的实现了:

// react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp

// ...
/** 
* script: bundle 内容(字符串)
* sourceURL: bundle 地址
*/
void JSIExecutor::loadApplicationScript(
    std::unique_ptr<const JSBigString> script,
    std::string sourceURL) {
  
  // 略去一些全局设置和 debug 下的代码

  if (runtimeInstaller_) {
    runtimeInstaller_(*runtime_);
  }

  // 略去日志输出代码
  
  // 关键代码:使用 webkit JSC 去真正解释执行Javascript了
  runtime_->evaluateJavaScript(
      std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
  flush();
  
  // 略去日志输出代码
}

// ...

void JSIExecutor::flush() {
  SystraceSection s("JSIExecutor::flush");
  // flushedQueue_ 还没被赋值,继续往下走
  if (flushedQueue_) {
    callNativeModules(flushedQueue_->call(*runtime_), true);
    return;
  }

  /** 
  * BatchedBridge.enqueueNativeCall 方法是否被调用过(如果 js 调用过 Java 模块,该方法也会被调用),如果被调用过,
  * 会在 global 对象上定义一个 __fbBatchedBridge 属性,其值是 BatchedBridge
  * BatchedBridge 是 MessageQueue 的一个实例,
  * 具体见:react-native/Libraries/BatchedBridge/BatchedBridge.js
  */
  Value batchedBridge =
      runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
  if (!batchedBridge.isUndefined()) {
    // 还没被调用过
    
    // 调用 bindBridge 方法绑定 js bridge,见下文
    bindBridge();
    callNativeModules(flushedQueue_->call(*runtime_), true);
  } else if (delegate_) {
    callNativeModules(nullptr, true);
  }
}

// ...

void JSIExecutor::bindBridge() {
  std::call_once(bindFlag_, [this] {
    SystraceSection s("JSIExecutor::bindBridge (once)");
    Value batchedBridgeValue =
        runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
    if (batchedBridgeValue.isUndefined()) {
      throw JSINativeException(
          "Could not get BatchedBridge, make sure your bundle is packaged correctly");
    }

    Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
    callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "callFunctionReturnFlushedQueue");
    invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "invokeCallbackAndReturnFlushedQueue");
    /** 
    * 对 flushedQueue_ 进行赋值
    * 通过webkit JSC 获取 MessageQueue.js 的 flushedQueue 属性值(函数)
    */    
    flushedQueue_ =
        batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
    callFunctionReturnResultAndFlushedQueue_ =
        batchedBridge.getPropertyAsFunction(
            *runtime_, "callFunctionReturnResultAndFlushedQueue");
  });
}

void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) {
  SystraceSection s("JSIExecutor::callNativeModules");
  // If this fails, you need to pass a fully functional delegate with a
  // module registry to the factory/ctor.
  CHECK(delegate_) << "Attempting to use native modules without a delegate";
#if 0 
  // 将函数 flushedQueue_ 的返回值 json 化
  std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
    .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
    .getString(*runtime_).utf8(*runtime_);
#endif
  // 调用 delegate_ 的 callNativeModules 方法
  delegate_->callNativeModules(
      *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}

// ...

JSIExecutor 的构造函数声明中可以看到,delegate_ 是类 ExecutorDelegate 的实例,其声明是在头文件 JSExecutor.h 中。

但类 ExecutorDelegate 是一个虚拟类,方法 callNativeModules 是一个虚拟方法(可类比 Java 中的抽象类和抽象方法来理解),因而这里实际调用的是其子类的对应方法:

// react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp

// ...
class JsToNativeBridge : public react::ExecutorDelegate {
public:
  // 构造函数
  JsToNativeBridge(std::shared_ptr<ModuleRegistry> registry,
                   std::shared_ptr<InstanceCallback> callback)
    : m_registry(registry)
    , m_callback(callback) {}
    
    
    // 重写父类的 callNativeModules
    void callNativeModules(
      __unused JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {

    CHECK(m_registry || calls.empty()) <<
      "native module calls cannot be completed with no native modules";
    m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();

    for (auto& call : parseMethodCalls(std::move(calls))) {
      // 调用 Native Registry 表中的java NativeMethod方法。
      m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
    }
    // isEndOfBatch 的值是 true
    if (isEndOfBatch) {

      // onBatchComplete will be called on the native (module) queue, but
      // decrementPendingJSCalls will be called sync. Be aware that the bridge may still
      // be processing native calls when the bridge idle signaler fires.
      if (m_batchHadNativeModuleCalls) {
        /** 
        * 回调 Java 端,通知 Java 端 js bundle 已经加载完成
        * m_callback 是 Java 类 BridgeCallback 的实例
        */
        m_callback->onBatchComplete();
        m_batchHadNativeModuleCalls = false;
      }
      m_callback->decrementPendingJSCalls();
    }
}
// ...

看到这里,你可能想知道 m_callback 是哪来的?

我们回想一下调用链路,在创建 CatalystInstance 实例的时候,同时会调用 C++ 层的 CatalystInstanceImpl::initializeBridge 方法,传入的第一个实数就是 BridgeCallback 实例,对应 C++ 层方法中第一个形参 callback。而在 CatalystInstanceImpl::initializeBridge 方法中又会调用 Instance::initializeBridge 方法,同时将 callback 作为一个参数透传,在 Instance::initializeBridge 方法中又会初始化 NativeToJsBridge 实例,同时将包装后的 callback 作为最后一个参数透传,在类 NativeToJsBridge 的构造函数中会初始化 JsToNativeBridge,将 callback 透传。

至此,js bundle 加载和解析流程完成了,我们回到Java代码中看看后续的流程。

回到 ReactInstanceManager

createReactContext 方法返回之后,继续往后执行:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...

private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
   // ...
   final ReactApplicationContext reactApplicationContext =
      createReactContext(
          initParams.getJsExecutorFactory().create(),
          initParams.getJsBundleLoader());

    mCreateReactContextThread = null;
   // ...
   
   Runnable setupReactContextRunnable =
      new Runnable() {
        @Override
        public void run() {
          try {
            setupReactContext(reactApplicationContext);
          } catch (Exception e) {
            mDevSupportManager.handleException(e);
          }
        }
      };

    reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
    // ...              
}

当线程任务 setupReactContextRunnable 启动之后,会去调用 setupReactContext 方法:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...
private void setupReactContext(final ReactApplicationContext reactContext) {
    // ...
    
    synchronized (mAttachedReactRoots) {
      synchronized (mReactContextLock) {
        mCurrentReactContext = Assertions.assertNotNull(reactContext);
      }

      CatalystInstance catalystInstance =
          Assertions.assertNotNull(reactContext.getCatalystInstance());
        
      // 初始化 Native Modules
      catalystInstance.initialize();

      // ...
      
      // 遍历 mAttachedReactRoots
      for (ReactRoot reactRoot : mAttachedReactRoots) {
        attachRootViewToInstance(reactRoot);
      }
      ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
    }
    
    // ...
}
// ...

先简单追溯一下 mAttachedReactRoots 被赋值的链路:mAttachedReactRoots 是在 ReactInstanceManager#attachRootView 方法中被赋值,attachRootView 方法是在 ReactRootView#attachToReactInstanceManager 方法中被调用,参数是 ReactRootView 实例,所以 mAttachedReactRoots 中保存的都是 ReactRootView 实例。

继续看 attachRootViewToInstance 方法的实现:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

// ...
private void attachRootViewToInstance(final ReactRoot reactRoot) {
    // ...
    
    // 将ReactRootView作为根布局
    UIManager uiManager =
        UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());
    
    // 获取初始化参数
    @Nullable Bundle initialProperties = reactRoot.getAppProperties();
    
    // 获取 rootTag
    final int rootTag =
        uiManager.addRootView(
            reactRoot.getRootViewGroup(),
            initialProperties == null
                ? new WritableNativeMap()
                : Arguments.fromBundle(initialProperties),
            reactRoot.getInitialUITemplate());
            
    // 设置 RootView 的 rootTag        
    reactRoot.setRootViewTag(rootTag);
    
    // RootView 的类型判断,默认类型是 DEFAULT
    if (reactRoot.getUIManagerType() == FABRIC) {
      // Fabric requires to call updateRootLayoutSpecs before starting JS Application,
      // this ensures the root will hace the correct pointScaleFactor.
      uiManager.updateRootLayoutSpecs(
          rootTag, reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec());
      reactRoot.setShouldLogContentAppeared(true);
    } else {
      // 调用 runApplication 方法
      reactRoot.runApplication();
    }
    
    // ...
}
// ...

回到 ReactRootView

继续看 runApplication 方法的实现:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

// ...

import com.facebook.react.modules.appregistry.AppRegistry;

// ...
  public void runApplication() {
      
      // ...

      ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
      if (reactContext == null) {
        return;
      }

      CatalystInstance catalystInstance = reactContext.getCatalystInstance();
      
      /** 
      * 获取 module name
      * 这个 module name 就是在 js 端调用 registerComponent 的第一个参数
      */
      String jsAppModuleName = getJSModuleName();

      if (mUseSurface) {
        // TODO call surface's runApplication
      } else {
        if (mWasMeasured) {
          updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec);
        }
        
        // 包装 RN 应用启动时的初始化参数
        WritableNativeMap appParams = new WritableNativeMap();
        appParams.putDouble("rootTag", getRootViewTag());
        @Nullable Bundle appProperties = getAppProperties();
        if (appProperties != null) {
          appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
        }

        mShouldLogContentAppeared = true;
        
        // 启动 RN 应用的入口
        catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
      }
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }
// ...

AppRegistry 类是 js 层暴露给 Java 层 JS module,所有的 JS module 都是接口,不能直接调用。但通过代理对象(AppRegistry.class),Java 对 JS 的调用就会有一个统一的入口:

// reac-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java

 // ...
    @Override
    public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
        throws Throwable {
      NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
      mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
      return null;
    }
 // ...    

从上述代码可知,所有 Java 对 JS 的调用都是通过 CatalystInstance#callFunction 方法实现,但最终都是通过 C++ 中的 CatalystInstanceImpl::jniCallJSFunction 方法实现的。

AppRegistry 类的具体实现在 AppRegistry.js 中:

 // ...
 
 registerComponent(
    appKey: string,
    componentProvider: ComponentProvider,
    section?: boolean,
  ): string {
    
    runnables[appKey] = {
      componentProvider,
      /** 
      * appParameters 是原生端初始化 RN 应用时透传的参数
      * 属性主要包含用于初始化的 initialProps,rootTag,fabric等
      */
      run: appParameters => {
        renderApplication(
          // ...
        )
      },
    };
    
    // ...
    return appKey;
  },
  
// ...
runApplication(appKey: string, appParameters: any): void {
    // ...
    runnables[appKey].run(appParameters);
  },
// ...

run 方法会去调用 renderApplication 方法去渲染 JS 组件,那 js 组件怎么和 Native 组件对应呢?

上文说到了,js bundle 执行之后会回调 Java:

// ...
       /** 
        * 回调 Java 端,通知 Java 端 js bundle 已经加载完成
        * m_callback 是 Java 类 BridgeCallback 的实例
        */
        m_callback->onBatchComplete();
        m_batchHadNativeModuleCalls = false;
// ...

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

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

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

image

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

<本文完>

参考

@ruan4261
Copy link

第一次知道居然有人拿github的issue当做博客, 这真是amazing啊 ^. ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants