React Native Android 源码分析之启动过程

前言

阅读以前请先查看准备工做javascript

这篇开始将分析 React Native 0.56-stable 分支 在 Android 端的启动过程是怎么样。java

用过 React Native 的小伙伴都知道,React Native 是可使用 JS 来编写一份代码,并能够同时跑在 Android 和 iOS 两个平台上。那其实核心思想就是 JS 跟 Android 之间创建起一种通讯机制。react

对于 Android 调用 JS 代码的方法有如下两种:android

  • 经过 WebViewloadUrl() 函数
  • 经过 WebViewevaluateJavascript() 函数

对于 JS 调用 Android 代码的方法有如下三种:c++

  • 经过 WebViewaddJavascriptInterface()进行对象映射
  • 经过 WebViewClientshouldOverrideUrlLoading() 方法回调拦截 url
  • 经过 WebChromeClientonJsAlert()onJsConfirm()onJsPrompt() 方法回调拦截 JS 对话框 alert()confirm()prompt() 消息

可是以上都是要基于 WebView 才能够实现,可是 React Native 并无使用 WebView 来实现 JS 和 Android 间的通讯,而是采用 JavaScriptCore 来实现 JS 的解析。编程

那分析 React Native 的启动过程,也就是分析 React Native 是如何让 Android 与 JavaScriptCore 进行关联的api

从 RNTester App Demo 出发

查看 React Native 项目 RNTester 下的 Android Demo。缓存

文中全部代码实例都只会截取核心代码,想查看完整代码请直接查看源码。网络

public class RNTesterApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public String getJSMainModuleName() {
      // js 入口文件地址
      return "RNTester/js/RNTesterApp.android";
    }

    @Override
    public @Nullable String getBundleAssetName() {
        // js bundle打包后 放在 asset 目录下的文件名称
      return "RNTesterApp.android.bundle";
    }
    
    ...
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }
};
复制代码

再看 RNTesterActivity.java 的代码app

public class RNTesterActivity extends ReactActivity {

    ...

  @Override
  protected String getMainComponentName() {
  // 用来返回要显示的js端的组件的名称,这个要和 js 端注册的 Component 名称一一对应
    return "RNTesterApp"; 
  }
}
复制代码

有点 React Native 的小伙伴知道,上面的 getJSMainModuleNamegetMainComponentName,必需要跟 JS 代码保持一直,不然运行程序会找不到对应的 JS 代码,可是为何要保持一直,这个疑问咱们先记下,继续日后面看。

能够看到 RNTesterActivity 是集成自 ReactActivityReactActivity 是 rn 中页面显示的入口,负责页面的显示。

进入 ReactActivityonCreate 中发现 ReactActivity 只是一个空壳子,全部的逻辑都交给 ReactActivityDelegate 类实现,这是典型的代理模式,这样作的好处:

  • 实现和接口分开
  • 能够在 FragmentActivity 也一样可使用,不用维护两套逻辑

查看 ReactActivityDelegateonCreate 发现最终是调用了 loadApp 函数

protected void loadApp(String appKey) {
    ...
    
    mReactRootView = createRootView();

    // rn 启动入口
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());

    // ReactRootView 做为 ReactActivity 的根 View
    getPlainActivity().setContentView(mReactRootView);
  }
复制代码

这个函数主要实现两个功能:

  • 建立 ReactRootView,并将这个 view 设置为当前 Activity 的根 view
  • 调用 ReactRootView 的 startReactApplication 方法,启动 rn 流

ReactRootView 继承 FrameLayout,它主要负责 native 端事件(键盘事件、touch事件、页面大小变化等)的监听并将结果传递给 js 端以及负责页面元素的从新绘制。涉及东西将多,以后会专门进行分析。

经过 startReactApplication 方法名也可知,这里才是 RN 启动的入口处。

RN 关键类登场

这里开始 RN 中的关键类就会陆续登场了。这里咱们先简单进行一下相关介绍,让读者有个印象。这里大部分的核心类都是采用面向接口编程的思想,括号中是接口对应的实现类。

ReactInstanceManager

rn 的 java 端的控制器,它主要的功能是建立和管理 CatalystInstance,ReactContext 实例并和 ReactActivity 的生命周期保持一致

CatalystInstance (CatalystInstanceImpl)

jsc 桥梁接口类,为 java 和 js 相互通讯提供环境。在 c++ 也有其对应的实现类

JSCJavaScriptExecutor

是 JavaScriptExecutor 的子类,是 js 执行器

JSBundleLoader

bundle.js 文件加载器,在 rn 中有三种加载方式:一、加载本地文件;二、加载网络文件,并将文件缓存;三、加载网络文件,用于 debug 调试。前面 Demo Applicatoin 类中的 getBundleAssetName 最终也是会转化为 JSBundleLoader

ModuleSpec

NativeModule的包装类,主要是为了实现 module 的懒加载,因为 rn 中 native module 比较多,为了节省成本,rn 中采用时懒加载的策略,只有相应的 module 使用时才进行建立。

JavaScriptModule

接口类,用于 java 调用 js 的接口,在 rn 中没有实现类,具体如何使用后面再介绍

JavaScriptModuleRegistry

JavaScriptModule 的注册表。

NativeModuleRegistry

NativeModule 的注册表,用于管理 NativeModule 列表。

NativeModule

java 暴露给 js 调用的 api 接口,若是想建立本身的 module,须要继承这个接口。

ReactPackage

组件配置接口类,经过 createNativeModules、createJSModules 和 createViewManagers 等API去建立本地模块,JS 模块及视图组件等。 ReactPackage 分为 rn 核心的 CoreModulesPackage 和业务方可选的基础 MainReactPackage 类,其中 CoreModulesPackage 封装了大部分通讯功能。

ReactContext

整个启动流程重要建立实例之一就是ReactContext, ReactContext继承于ContextWrapper,是ReactNative应用的上下文,经过getContext()去得到,经过它能够访问ReactNative核心类的实现。

继续分析源码

以上就是 RN 中反复出现的关键类。接着跟着源码走

// ReactRootView.java
public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties) {
        ...
        
      if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
        // 
        mReactInstanceManager.createReactContextInBackground();
      }
    
      attachToReactInstanceManager();

        ...
  }
复制代码

咱们此次先来看 attachToReactInstanceManager 函数,看代码这个函数会在 ReactContext 建立以后才会调用。继续深刻发现最终到了 ReactInstanceManager 的调用

// ReactInstanceManager.java

  private void attachRootViewToInstance( final ReactRootView rootView, CatalystInstance catalystInstance) {
    ...
    // 最终调用 AppRegistry.js 的 runApplication 方法
    rootView.invokeJSEntryPoint();
    ...
  }
复制代码

发现最终又回到了 ReactRootView 中

// ReactRootView.java
  private void defaultJSEntryPoint() {
        ...
        ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
        if (reactContext == null) {
          return;
        }

        CatalystInstance catalystInstance = reactContext.getCatalystInstance();

        ...

        String jsAppModuleName = getJSModuleName();
        
        // 调用 js module
        catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
  }
复制代码

在这里咱们发现了一个很是眼熟的类名 AppRegistry.class, 这个不就是在全部入口 js 中都要写的一行代码中的 AppRegistry

AppRegistry.registerComponent('RNTesterApp', () => RNTesterApp);
复制代码

因此 defaultJSEntryPoint 函数最终调起了 js 的入口。 再看 defaultJSEntryPoint 函数,发现里面同时用到了 ReactContextCatalystInstanceReactInstanceManager。因此验证了他们三者相互之间的重要关系。也说明了 React Native 的启动重要的就是要建立 ReactContext。至于 Java 是如何调用的 JS,咱们稍后再分析,如今咱们来分析 ReactContext 是如何建立的。

沿着 createReactContextInBackground 的函数流,会发现最终不论是采用加载网络仍是本地的 bundle 文件最终都是会到达 runCreateReactContextOnNewThread 方法中

// ReactInstanceManager.java
  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
    ...
    mCreateReactContextThread =
        new Thread(
            new Runnable() {
              @Override
              public void run() {
                    ...
                  // 核心部分,建立 ReactContext
                  final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());

                  mCreateReactContextThread = null;
                  ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_START);
                    ...
                  Runnable setupReactContextRunnable =
                      new Runnable() {
                        @Override
                        public void run() {
                          try {
                            // 最终会调用 attachRootViewToInstance 即调用 defaultJSEntryPoint 启动 js 入口
                            setupReactContext(reactApplicationContext);
                          } catch (Exception e) {
                            mDevSupportManager.handleException(e);
                          }
                        }
                      };

                    ...
                  UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
              }
            });
    // 启动新线程
    mCreateReactContextThread.start();
  }
复制代码

这个函数主要作了如下几件事:

  1. 若是已存在 ReactContext,将其进行销毁
  2. 开启一个新的线程用于建立 ReactContext
  3. ReactContext 建立成功以后,在 UI 线程中最终函数流会调用 defaultJSEntryPoint 方法来启动 js 的入口程序

硬骨头 createReactContext

接下来才是整个 RN 的硬骨头,只要将其啃下,对 RN 底层的实现也就理解了。由于这里主要涉及到了 C++ 层面的核心实现,且代码实现较长,故不会将代码都贴出来,仍是但愿读者能够结合着源码和这篇文章来分析这块。

先上createReactContext 函数代码

private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
        ...
    // 将核心 CoreModulesPackage 和 业务基础 MainReactPackage 中的 NativeModule 添加到注册表中
    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);

    CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
      .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) // 初始化 native 线程队列及 js 线程队列
      .setJSExecutor(jsExecutor) // js 执行器
      .setRegistry(nativeModuleRegistry) // 本地提供给 JS 调用的 NativeModule 注册表
      .setJSBundleLoader(jsBundleLoader) // bundle 信息类
      .setNativeModuleCallExceptionHandler(exceptionHandler);
        ...
    final CatalystInstance catalystInstance;
        ...
      catalystInstance = catalystInstanceBuilder.build();
        ...
    // 加载 js bundle 文件
    catalystInstance.runJSBundle();
    
    reactContext.initializeWithInstance(catalystInstance);

    return reactContext;
  }
复制代码

这个函数主要作了如下功能:

  1. 根据 ReactPackage 列表生成 Native Module 的注册表
  2. 建立 Native 及 JS 的线程队列
  3. 建立 CatalystInstance 实例
  4. 加载 bundle 文件
  5. 将 UI,Native 及 JS 的线程队列赋予 ReactContext

CatalystInstanceImpl 做为整个 RN 中举足轻重的角色,来看一下它的构造函数。

private CatalystInstanceImpl( final ReactQueueConfigurationSpec reactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry nativeModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    // 找到于java相对应的c++类并调用其构造方法生成对象
    mHybridData = initHybrid();

    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++ 中对应的实现
    initializeBridge(
      new BridgeCallback(this),
      jsExecutor,
      mReactQueueConfiguration.getJSQueueThread(),
      mNativeModulesQueueThread,
      mNativeModuleRegistry.getJavaModules(this),
      mNativeModuleRegistry.getCxxModules());

    // JSGlobalContextRef 的内存地址
    mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
  }
复制代码

构造函数中有两个须要关注的地方

  1. HybridData 对象在 rn 中会反复的出现,它的主要做用是找到于 java 相对应的 c++ 类并调用其构造方法生成对象,把 new 出来对象的地址放到 java 的 HybridData 对象中
  2. ReactQueueConfigurationSpec:用于配置消息线程,在 rn 中有三个消息线程:UI 线程、JS 线程、Native 线程,其中 native 调用 js 的代码会 JS 线程运行,JS 调用 native 的代码会在 Native 线程中执行

C++ 层核心类登场

在继续以前须要讲解一下 Native 层的核心类

NativeToJsBridge

NativeToJsBridge是Java调用JS的桥梁,用来调用JS Module,回调Java

JsToNativeBridge

JsToNativeBridge是JS调用Java的桥梁,用来调用Java Module

JSCExecutor

native 层的 js 执行器

CatalystInstanceImpl

CatalystInstanceImpl 在 c++ 层对应的实现

Instance

能够看做是 NativeToJsBridge 的代理类,最终的处理都是交由了 NativeToJsBridge

分析 Native 层

从这里开始将会讨论 Native 层对应的操做,上面提到 createReactContext 函数里进行了 CatalystInstanceImpl 的初始化,而最终的核心实际上是在 Native 进行的。看一下 Native 层中 CatalystInstanceImplinitializeBridge 函数

// 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) {

  moduleMessageQueue_ = std::make_shared<JMessageQueueThread>(nativeModulesQueue);

    // 在 native 层将 JavaNativeModule 和 CxxNativeModule 保存到 注册表里
  moduleRegistry_ = std::make_shared<ModuleRegistry>(
    buildNativeModuleList(
       std::weak_ptr<Instance>(instance_),
       javaModules,
       cxxModules,
       moduleMessageQueue_));

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

这个函数主要作了如下几个功能:

  1. 将 java 层的对象分装成 JavaNativeModule 和 CxxNativeModule 对象,并将生成的对象注册到 ModuleRegistry 对象中,ModuleRegistry和上面提升的 NativeModuleRegistry 功能类似,是 C++ 端 module 的注册表, 而且将 java 的 MessageQueueThread 也传入每一个 NativeModule 中以便以后能够直接调用
  2. 跳转到 Instance.cpp 的 initializeBridge 方法中
// Instance.cpp
void Instance::initializeBridge(
    std::unique_ptr<InstanceCallback> callback,
    std::shared_ptr<JSExecutorFactory> jsef,
    std::shared_ptr<MessageQueueThread> jsQueue,
    std::shared_ptr<ModuleRegistry> moduleRegistry) {
  callback_ = std::move(callback); // 含有
  moduleRegistry_ = std::move(moduleRegistry);

    // 在 js 线程队列中初始化 NativeToJsBridge
  jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
      // 初始化 NativeToJsBridge
    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();
  });
    ...
}
复制代码

这个函数主要就是在 js 的线程队列中初始化 NativeToJsBridge,上面也提升了 NativeToJsBridge 类是 Java 调用 JS 的桥梁,用来调用 JS Module,回调 Java

// NativeToJsBridge.cpp
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)) // 初始化 JsToNativeBrdige 打通 js 调用 native 的桥梁
    , m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue)) // js 的执行器
    , m_executorMessageQueueThread(std::move(jsQueue)) // js 线程队列
    {}
复制代码

NativeToJsBridge 的构造函数主要是初始化了通讯所需的关键类

m_delegateJsToNativeBridge,用于 JS 调用 Native 函数,和 NativeToJsBridge 一块儿做为链接 java 和 js 通讯的桥梁

m_executor 是对应于 JSCExecutor 对象,JSCExecutor 构造函数中对 js 的执行环境进行初始化,而且向 JavaScriptCore 中注册了几个 c++ 的方法供 js 端调用

到这里 initializeBridge 整个函数就所有介绍完毕了, 总结一句就是在 ReactInstanceManagercreateReactContext 函数里初始化 CatalystInstanceImpl 时,会经过 JNI 在 Native 层中初始化 Java 与 JS 通讯所需的关键类,将通讯环境搭建完成。

加载 JS Bundle

继续查看 createReactContext 的源码,看到在 CatalystInstanceImpl 初始化以后会接着调用 CatalystInstanceImplrunJSBundle 方法。经过函数的名字能够直接这个方法将会真正的去加载 JS Bundle 文件。

查看 runJSBundle 的源码发现最终是走到了 JSBundleLoaderloadScript 函数里。 JSBundleLoader 上面介绍过,是来管理 JS Bundle 的加载方式,无论采用哪一种加载方式,最终都是回到CatalystInstanceImpl 进行处理。

private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
private native void jniLoadScriptFromDeltaBundle(String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously);
复制代码

能够看到 CatalystInstanceImpl 中对应上面提到的三种加载 JS Bundle 的方式,而都是在 Native 层进行处理。

仅需进行代码追踪,会发现三种方法都是在 NativeToJsBridge 中进行了统一处理

// NativeToJsBridge.cpp
void NativeToJsBridge::loadApplication(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {
  runOnExecutorQueue( // js 线程队列
      [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));
    }
    executor->loadApplicationScript(std::move(*startupScript),
                                    std::move(startupScriptSourceURL));
  });
}
复制代码

executor 对应的 JSCExecutor 在上面已经说过, 是 JS 的执行器。

// JSCExecutor.cpp
void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) {
    ...
    //JavaScriptCore函数,执行js代码
    evaluateScript(m_context, jsScript, jsSourceURL);
 
    ...
    flush();
    ...
  }
}
复制代码

loadApplicationScript 函数代码较多,可是最核心的就是 flush 函数

void JSCExecutor::flush() {
  SystraceSection s("JSCExecutor::flush");

  if (m_flushedQueueJS) {
    callNativeModules(m_flushedQueueJS->callAsFunction({}));
    return;
  }

  // When a native module is called from JS, BatchedBridge.enqueueNativeCall()
  // is invoked. For that to work, require('BatchedBridge') has to be called,
  // and when that happens, __fbBatchedBridge is set as a side effect.
  auto global = Object::getGlobalObject(m_context);
  auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
  // So here, if __fbBatchedBridge doesn't exist, then we know no native calls
  // have happened, and we were able to determine this without forcing
  // BatchedBridge to be loaded as a side effect.
  if (!batchedBridgeValue.isUndefined()) {
    // If calls were made, we bind to the JS bridge methods, and use them to
    // get the pending queue of native calls.
    bindBridge();
    callNativeModules(m_flushedQueueJS->callAsFunction({}));
  } else if (m_delegate) {
    // If we have a delegate, we need to call it; we pass a null list to
    // callNativeModules, since we know there are no native calls, without
    // calling into JS again. If no calls were made and there's no delegate,
    // nothing happens, which is correct.
    callNativeModules(Value::makeNull(m_context));
  }
}
复制代码

flush 函数主要就是检查是否已经加载过 js bundle,创建了链接桥梁。若是没有就调用 bindBridge 进行链接。

void JSCExecutor::bindBridge() throw(JSException) {
  SystraceSection s("JSCExecutor::bindBridge");
  std::call_once(m_bindFlag, [this] {
      // 获取 js 中的 global 对象
    auto global = Object::getGlobalObject(m_context);

      // 获取存储在 global 中的 MessageQueue 对象
    auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
    if (batchedBridgeValue.isUndefined()) {
      auto requireBatchedBridge =
          global.getProperty("__fbRequireBatchedBridge");
      if (!requireBatchedBridge.isUndefined()) {
        batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
      }
      if (batchedBridgeValue.isUndefined()) {
        throw JSException(
            "Could not get BatchedBridge, make sure your bundle is packaged correctly");
      }
    }

      // 在 native 中保存 MessageQueue 关键的函数对象
    auto batchedBridge = batchedBridgeValue.asObject();
    m_callFunctionReturnFlushedQueueJS =
        batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
    m_invokeCallbackAndReturnFlushedQueueJS =
        batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue")
            .asObject();
    m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
    m_callFunctionReturnResultAndFlushedQueueJS =
        batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue")
            .asObject();
  });
}
复制代码

这个函数主要实现如下功能: 一、从 js 执行环境中取出全局变量 fbBatchedBridge 放到 global 变量中 二、将 global 中某些特定的函数对象映射到 C++ 对象中,这样咱们就能够经过 C++ 对象调用 js 的代码,假设咱们想要调用 js 端 fbBatchedBridge 的 flushQueue 方法,在 C++ 中就可使用 m_flushedQueueJS->callAsFunction() 就能够实现,那么 fbBatchedBridge 在 js 端究竟是个什么东西那?

查看 BatchBridge.js 中能够找到 __fbBatchedBridge 的定义

const MessageQueue = require('MessageQueue');

const BatchedBridge = new MessageQueue();

Object.defineProperty(global, '__fbBatchedBridge', {
  configurable: true,
  value: BatchedBridge,
});

module.exports = BatchedBridge;
复制代码

能够看出 __fbBatchedBridge 指的就是 JS 中的 MessageQueue 对象,这样就实现了 Android 端的消息队列和 JS 端消息队列的连通。

总结

对上面的源码流程作了个核心方法的调用流程图

相关文章
相关标签/搜索