React Native 代码阅读(六):C++ 侧的 Instance 类

2019-02-19

前言

Instance 是 React Native 在 C++ 侧非常重要的一个类。初始化 Bridge、加载 Bundle 都通过它完成。在本文中,我们先来分析它在整个 React Native 框架中的位置。

实例创建

Instance 实例是何时创建的呢?

Instance 是 CatalystInstanceImpl 的成员 instance_ ,在 CatalystInstanceImpl 的构造函数中一同创建。

Instance 创建实例后,需要外界调用它的 initializeBridge 方法来初始化。这一步位于 CatalystInstanceImpl::initializeBridge 中。

我们来看 Instance::initializeBridge 方法,CatalystInstanceImpl::initializeBridge 外部调用代码为:

instance_->initializeBridge(
    folly::make_unique<JInstanceCallback>(
        callback,
        moduleMessageQueue_),
    jseh->getExecutorFactory(),
    folly::make_unique<JMessageQueueThread>(jsQueue),
    moduleRegistry_);

在 Instance::initializeBridge 的方法签名:

void Instance::initializeBridge(
    std::unique_ptr<InstanceCallback> callback,
    std::shared_ptr<JSExecutorFactory> jsef,
    std::shared_ptr<MessageQueueThread> jsQueue,
    std::shared_ptr<ModuleRegistry> moduleRegistry) {

我们可以对照来看。其内部逻辑是:

首先存下 callback 和 moduleRegistry:

callback_ = std::move(callback);
moduleRegistry_ = std::move(moduleRegistry);

之后向 jsQueue 上扔了一个闭包:

jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
    nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
        jsef.get(), moduleRegistry_, jsQueue, callback_);

    std::lock_guard<std::mutex> lock(m_syncMutex);
    m_syncReady = true;
    m_syncCV.notify_all();
});

其中,主要操作是存下 nativeToJsBridge_

这样即完成了初始化操作。

NativeToJsBridge

介绍

上文中的 NativeToJsBridge 是什么呢?

它位于 ReactCommon/cxxreact/NativeToJsBridge.h,注解为:

这个类管理从 Native 代码到 JS 的调用。他还管理执行器和他们的线程。这里所有的方法都可以在任意线程中调用。

除了 loadApplicationScriptSync 之外,所有的 void 方法都要扔到 jsQueue 上运行,并立刻返回。

执行器(Executor)

在注释中提到了执行器,我们快速回顾一下 Executor 是什么。它对应的类是 JSExecutor,这个类是一个基类,它的作用是隔离各种运行时(其实总共就一种)。

基于它派生出 JSCExecutor,它是 JavaScriptCore 的封装层,也就是 JS 引擎了。

我们再来看 NativeToJsBridge 的构造函数:

NativeToJsBridge::NativeToJsBridge(
    JSExecutorFactory* jsExecutorFactory,
    std::shared_ptr<ModuleRegistry> registry,
    std::shared_ptr<MessageQueueThread> jsQueue,
    std::shared_ptr<InstanceCallback> callback)
    : m_destroyed(std::make_shared<bool>(false))
    , m_delegate(std::make_shared<JsToNativeBridge>(registry, callback))
    , m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue))
    , m_executorMessageQueueThread(std::move(jsQueue)) {}

其中 m_executor 这行我们可以看出,NativeToJsBridge 从 Holder 中自己创建了一个 JS 运行时。

NativeToJsBridge 中各种方法则是基于运行时封装出的能力。

回到 Instance

NativeToJsBridge 弄清楚后,我们回到 Instance。

Instance 将 NativeToJsBridge 实例存放在 nativeToJsBridge_ 成员中。

Instance 基于 NativeToJsBridge 提供的 JS 运行时,提供了一下能力:

  • loadApplication 执行 JS 应用代码
  • loadApplicationSync 同步执行 JS 应用代码
  • setSourceURL 设置 sourceURL
  • loadScriptFromString 根据 string 执行 JS 代码
  • loadRAMBundleFromFile 加载 RAMBundle 代码
  • callJSFunction 调用 JS 方法
  • registerBundle 注册 Bundle

CatalystInstanceImpl 对 Instance 的使用

Instance 作为 CatalystInstanceImpl 的成员,CatalystInstanceImpl 是如何使用它的呢?

CatalystInstanceImpl::extendNativeModules:

  • 实际调用 moduleRegistry_->registerModules

CatalystInstanceImpl::jniSetSourceURL:

  • 实际调用 instance_->setSourceURL(sourceURL);

CatalystInstanceImpl::jniRegisterSegment:

  • 实际调用 instance_->registerBundle

CatalystInstanceImpl::jniLoadScriptFromAssets:

  • 实际调用 instance_->loadRAMBundle

在这里省略一些方法。因为已经足够看出,CatalystInstanceImpl 中大部分方法都是加载 JS bundle,与运行时打交道,而这些与运行时相关的具体操作,都代理封装在了 Instance 中。

CatalystInstanceImpl::getInstance()

在 CatalystInstanceImpl 中还有一个方法,即 CatalystInstanceImpl::getInstance(),外界可以通过它获取 Instance 实例。在外部都有哪些类使用到它呢?

找了一圈,原来并没有调用的地方。

小结

至此我们可以得出 Instance 类的作用是做什么的了:

  • 它是 CatalystInstanceImpl 与 JavaScriptCore 之间的中间层
  • 它向下封装了一些列 JavaScript 运行时 API,向上提供给 CatalystInstanceImpl
  • CatalystInstanceImpl 通过代理模式获得了 Instance 的能力,对外提供这组 API