IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React Native 源码分析(二)——通信机制 -> 正文阅读

[JavaScript知识库]React Native 源码分析(二)——通信机制

本篇来分析一下,RN js和java的通信机制,在上一篇启动流程 看完后,通信的过程,你应该也能猜出个大概。具体过程,也是很简单

1、React Native 源码分析(一)—— 启动流程
2、React Native 源码分析(二)—— 通信机制
3、React Native 源码分析(三)—— UI渲染流程
4、React Native 源码分析(四)—— 任务调度
5、React Native 源码分析(五)—— 事件分发

一、 Java->JS 通信

先来一张图,看一下通信的整体过程
图片来源
在这里插入图片描述

这里接着上一篇的代码1.9 reactRoot.runApplication(); 继续分析,从java启动react的过程

1.1 runApplication

  @Override
  public void runApplication() {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
    try {
      if (mReactInstanceManager == null || !mIsAttachedToInstance) {
        return;
      }

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

      CatalystInstance catalystInstance = reactContext.getCatalystInstance();
      //在自己的activity中,指定的mainComponentName名称
      String jsAppModuleName = getJSModuleName();
      //onMeasure执行后,该变量会设为true,如果再次调用到runApplication,需要重新绘制
      if (mWasMeasured) {
        //本质是会通过FabricUIManager或UIManagerModule 来更新界面
        updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec);
      }

      WritableNativeMap appParams = new WritableNativeMap();
      appParams.putDouble("rootTag", getRootViewTag());
      @Nullable Bundle appProperties = getAppProperties();
      if (appProperties != null) {
        appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
      }

      mShouldLogContentAppeared = true;
      //启动js中的 AppRegistry register的Component,并传入参数appParams
      catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

getJSModule的调用流程catalystInstance.getJSModule ->mJSModuleRegistry.getJavaScriptModule,调用到了JavaScriptModuleRegistry中,这里是通过动态代理的方式,让 继承了JavaScriptModule的Interface中的方法的 调用,都被代理到 mCatalystInstance.callFunction

2、JavaScriptModuleRegistry # getJavaScriptModule

public final class JavaScriptModuleRegistry {
  private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;

  public JavaScriptModuleRegistry() {
    mModuleInstances = new HashMap<>();
  }
  //catalystInstance.getJSModule 调到这里
  public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
      CatalystInstance instance, Class<T> moduleInterface) {
    JavaScriptModule module = mModuleInstances.get(moduleInterface);
    if (module != null) {
      return (T) module;
    }

    JavaScriptModule interfaceProxy =
        (JavaScriptModule)
            Proxy.newProxyInstance(
                moduleInterface.getClassLoader(),
                //此时指的是AppRegistry.class
                new Class[] {moduleInterface},
                new JavaScriptModuleInvocationHandler(instance, moduleInterface));
    mModuleInstances.put(moduleInterface, interfaceProxy);
    return (T) interfaceProxy;
  }

  private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
    private final CatalystInstance mCatalystInstance;
    private final Class<? extends JavaScriptModule> mModuleInterface;
    private @Nullable String mName;

    public JavaScriptModuleInvocationHandler(
        CatalystInstance catalystInstance, Class<? extends JavaScriptModule> moduleInterface) {
      mCatalystInstance = catalystInstance;
      mModuleInterface = moduleInterface;
      ...
    }

   ....

    @Override
    public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
        throws Throwable {
      NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
      //getJSModuleName 获取js module的类名,method.getName() 调用的方法名,jsArgs 传入的参数
      //下面分析该函数
      mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
      return null;
    }
  }

    ....
}

1.3 CatalystInstance的函数 callFunction 和 runJSBundle

  public void callFunction(PendingJSCall function) {
    if (mDestroyed) {
      final String call = function.toString();
      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed: " + call);
      return;
    }
    //如果js bundle还未加载,就把任务加入到mJSCallsPendingInit,直接返回
    if (!mAcceptCalls) {
      // Most of the time the instance is initialized and we don't need to acquire the lock
      synchronized (mJSCallsPendingInitLock) {
        if (!mAcceptCalls) {
          mJSCallsPendingInit.add(function);
          return;
        }
      }
    }
    function.call(this);
  }

mAcceptCalls 的初始值是false,callFunctionrunJSBundle 都是从React Native 源码分析(一)—— 启动流程的代码1.4的 runCreateReactContextOnNewThread,callFunction 是在nativeModule线程运行,由于并发的原因,为了保证js bundle加载后,再去调用js的函数。引入mAcceptCalls 来控制,

  @Override
  public void runJSBundle() {
    //上篇文章代码1.4分析的,mJSBundleLoader 有几种类型,由js bundle的位置来决定
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);

    synchronized (mJSCallsPendingInitLock) {

      // Loading the bundle is queued on the JS thread, but may not have
      // run yet.  It's safe to set this here, though, since any work it
      // gates will be queued on the JS thread behind the load.
      mAcceptCalls = true;

      for (PendingJSCall function : mJSCallsPendingInit) {
        function.call(this);
      }
      mJSCallsPendingInit.clear();
      mJSBundleHasLoaded = true;
    }
  }

最终都是调用了function.call(this);,下面来分析该函数

1.4 PendingJSCall # call

    void call(CatalystInstanceImpl catalystInstance) {
      NativeArray arguments = mArguments != null ? mArguments : new WritableNativeArray();
      //这里调用到c++ 层
      catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);
    }

1.5 CatalystInstanceImpl::jniCallJSFunction

void CatalystInstanceImpl::jniCallJSFunction(
    std::string module,
    std::string method,
    NativeArray *arguments) {
  // We want to share the C++ code, and on iOS, modules pass module/method
  // names as strings all the way through to JS, and there's no way to do
  // string -> id mapping on the objc side.  So on Android, we convert the
  // number to a string, here which gets passed as-is to JS.  There, they they
  // used as ids if isFinite(), which handles this case, and looked up as
  // strings otherwise.  Eventually, we'll probably want to modify the stack
  // from the JS proxy through here to use strings, too.
  instance_->callJSFunction(
      std::move(module), std::move(method), arguments->consume());
}

1.6 Instance::callJSFunction

void Instance::callJSFunction(
    std::string &&module,
    std::string &&method,
    folly::dynamic &&params) {
    //该回调是在上篇文章的代码1.7 的new BridgeCallback(this) 创建的
  callback_->incrementPendingJSCalls();
  //该变量 在上篇文章,也有介绍,下面直接看callFunction
  nativeToJsBridge_->callFunction(
      std::move(module), std::move(method), std::move(params));
}

1.7 NativeToJsBridge::callFunction

void NativeToJsBridge::callFunction(
    std::string &&module,
    std::string &&method,
    folly::dynamic &&arguments) {
   ...

  //把lambda代码发送到js线程队列,所以java->js的通信是异步的
  runOnExecutorQueue([this,
                      module = std::move(module),
                      method = std::move(method),
                      arguments = std::move(arguments),
                      systraceCookie](JSExecutor *executor) {
    if (m_applicationScriptHasFailure) {
    ...
    // This is safe because we are running on the executor's thread: it won't
    // destruct until after it's been unregistered (which we check above) and
    // that will happen on this thread
    //executor 这里作为lambda的parameter,argument 传的是m_executor(上篇文章代码2.5 被赋值)
    executor->callFunction(module, method, arguments);
  });
}

最终调用m_executor ,(本例)也就是JSIExecutor 的callFunction,(也可能是其他的jsexecutor 的callFunction)

1.8 JSIExecutor:: callFunction

void JSIExecutor::callFunction(
    const std::string &moduleId,
    const std::string &methodId,
    const folly::dynamic &arguments) {

  if (!callFunctionReturnFlushedQueue_) {
    //把js 中的函数映射到c++层,例如这里的callFunctionReturnFlushedQueue_
    bindBridge();
  }
  ...
  try {
    scopedTimeoutInvoker_(
        [&] {
          //调用js 的同名函数
          ret = callFunctionReturnFlushedQueue_->call(
              *runtime_,
              moduleId,
              methodId,
              valueFromDynamic(*runtime_, arguments));
        },
        std::move(errorProducer));
  } catch (...) {
    std::throw_with_nested(
        std::runtime_error("Error calling " + moduleId + "." + methodId));
  }
  //返回值,传到java
  callNativeModules(ret, true);
}

下面到js看看,callFunctionReturnFlushedQueue_ 的实现

1.9 MessageQueue & callFunctionReturnFlushedQueue

MessageQueue 类的位置在 Libraries/BatchedBridge/MessageQueue.js

  callFunctionReturnFlushedQueue(
    module: string,
    method: string,
    args: mixed[],
  ): null | [Array<number>, Array<number>, Array<mixed>, number] {
    this.__guard(() => {
       //找到对应的module,调用方法
      this.__callFunction(module, method, args);
    });
    //这个会调用 JSTimer 的callImmediates
    return this.flushedQueue();
  }

  __callFunction(module: string, method: string, args: mixed[]): void {
    this._lastFlush = Date.now();
    this._eventLoopStartTime = this._lastFlush;
    ...
    //从_lazyCallableModules 中取出对应的module
    const moduleMethods = this.getCallableModule(module);
    ...
    //moduleMethods[method] 方法名,用 apply 来调用 
    moduleMethods[method].apply(moduleMethods, args);
   
  }

至此,java-> js 的通信流程就分析完了,下面来看看js->java的

二、 JS->Java 通信

在开始分析之前,首先要知道,JS->Java 通信是两种的,表现在通信中的差异,下面会介绍一些。具体原因是传递的 JavaScriptExecutorFactory不同(可在ReactNativeHost中设置),但是 如果你本地跑了metro,那么会自动使用 ProxyJavaScriptExecutor(可自己翻阅代码 ReactInstanceManager 的onReloadWithJSDebugger函数)

我们在JS中调用Java的方法,是通过这样的形式

  1. 继承 ReactContextBaseJavaModule,使用@ReactMethod 注解 暴露给js的方法,
  2. 把 上一步创建的类 添加到ReactPackage
  3. 把ReactPackage添加到ReactNativeHost 的getPackages() 的返回值中
  4. 在js侧,通过NativeModules.xxxModuleName.xxxMethodName() 调用到原生

下面我们就从 NativeModules.xxxModuleName 这样的代码开始分析:

先来看张图,对整体过程,有个感觉。图片来源
在这里插入图片描述

首先需要搞清楚,这个NativeModules 是什么,在js侧,代码路径 Libraries/BatchedBridge/NativeModules.js

2.1、 NativeModules.js

let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};
if (global.nativeModuleProxy) {
  //nativeModuleProxy 的赋值,是在 JSIExecutor::initializeRuntime() ,详见上篇文章
  //如果执行到这里,那么JavaScriptExecutor 使用的是JSIExecutor
  NativeModules = global.nativeModuleProxy;
} else if (!global.nativeExtensions) {

  //如果你是debug,本地跑metro服务,会运行到这里
  const bridgeConfig = global.__fbBatchedBridgeConfig;

  const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');
  (bridgeConfig.remoteModuleConfig || []).forEach(
    (config: ModuleConfig, moduleID: number) => {
      // Initially this config will only contain the module name when running in JSC. The actual
      // configuration of the module will be lazily loaded.
      const info = genModule(config, moduleID);
      if (!info) {
        return;
      }

      if (info.module) {
        NativeModules[info.name] = info.module;
      }
      // If there's no module config, define a lazy getter
      else {
        defineLazyObjectProperty(NativeModules, info.name, {
          get: () => loadModule(info.name, moduleID),
        });
      }
    },
  );
}

module.exports = NativeModules;

不同的JavaScriptExecutor 最终都会执行到genModule,下面我们分析JSIExecutor 分支 的流程。

简单回忆一下,在 JSIExecutor::initializeRuntime() 中设置了 global.nativeModuleProxy 的值,

  runtime_->global().setProperty(
      *runtime_,
      "nativeModuleProxy",
      Object::createFromHostObject(
          *runtime_, std::make_shared<NativeModuleProxy>(nativeModules_)));

可以看到global.nativeModuleProxy 是NativeModuleProxy 类型,在获取对应的module,会执行NativeModuleProxy的get方法,下面来到c++层:

2.2、 JSIExecutor::NativeModuleProxy

class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
 public:
  NativeModuleProxy(std::shared_ptr<JSINativeModules> nativeModules)
      : weakNativeModules_(nativeModules) {}

  Value get(Runtime &rt, const PropNameID &name) override {
     ...
    auto nativeModules = weakNativeModules_.lock();
    if (!nativeModules) {
      return nullptr;
    }
    //调用 JSIExecutor的getModule
    return nativeModules->getModule(rt, name);
  }

 ...

 private:
  std::weak_ptr<JSINativeModules> weakNativeModules_;
};

2.3、 JSIExecutor # getModule

Value JSINativeModules::getModule(Runtime &rt, const PropNameID &name) {
  if (!m_moduleRegistry) {
    return nullptr;
  }
  
  std::string moduleName = name.utf8(rt);
  //先从缓存中查找,如果已经被加载过,直接返回
  const auto it = m_objects.find(moduleName);
  if (it != m_objects.end()) {
    ...
    return Value(rt, it->second);
  }
  // 缓存没有命中,创建module。
  // 创建module,解析module对应的method,为每个method创建对应的js方法(用于把对应的调用信息,发送到js线程队列)
  auto module = createModule(rt, moduleName);
  ...省略判空逻辑...
  // 把创建的module缓存起来
  auto result = m_objects.emplace(std::move(moduleName), std::move(*module)).first;
  
  Value ret = Value(rt, result->second);
  //直接返回给js了
  return ret;
}

createModule 是核心,下面来分析

2.4 JSINativeModules::createModule

folly::Optional<Object> JSINativeModules::createModule(
    Runtime &rt,
    const std::string &name) {
  //获取到js层的__fbGenNativeModule ,在NativeModule.js中有这句 global.__fbGenNativeModule = genModule;
  if (!m_genNativeModuleJS) {
    m_genNativeModuleJS =
        rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");
  }
  //获取对应name的module,代码2.5 分析
  auto result = m_moduleRegistry->getConfig(name);
  if (!result.hasValue()) {
    return folly::none;
  }
  //调用到js层,genModule->去解析module, genMethod-> 创建该module的所有method所需的方法.代码2.6分析
  Value moduleInfo = m_genNativeModuleJS->call(
      rt,
      valueFromDynamic(rt, result->config),
      static_cast<double>(result->index));

  folly::Optional<Object> module(
      moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));
  
  return module;
}

m_moduleRegistry->getConfig(name); 的结果,会传递到js中去处理module,下面来分析一下这句代码

2.5 ModuleRegistry::getConfig

folly::Optional<ModuleConfig> ModuleRegistry::getConfig(
    const std::string &name) {
  SystraceSection s("ModuleRegistry::getConfig", "module", name);

  // Initialize modulesByName_
  if (modulesByName_.empty() && !modules_.empty()) {
    //把modules_中的每个名称作为key,索引作为value,存入modulesByName_
    //modules_ 的值,是在上篇文章的 CatalystInstanceImpl::initializeBridge 函数中传入的
    moduleNames();
  }
 
  auto it = modulesByName_.find(name);
  //不知道为什么要和最后一个比较,知道的小伙伴,在评论区指导一下
  if (it == modulesByName_.end()) {
    if (unknownModules_.find(name) != unknownModules_.end()) {
      return folly::none;
    }

    //moduleNotFoundCallback_是一个回调函数,在构造函数ModuleRegistry::ModuleRegistry 中赋值
    if (!moduleNotFoundCallback_) {
      //没有回调 把module 名称存储,返回
      unknownModules_.insert(name);
      return folly::none;
    }

    
    bool wasModuleLazilyLoaded = moduleNotFoundCallback_(name);
    it = modulesByName_.find(name);

    bool wasModuleRegisteredWithRegistry =
        wasModuleLazilyLoaded && it != modulesByName_.end();

    if (!wasModuleRegisteredWithRegistry) {
      unknownModules_.insert(name);
      return folly::none;
    }
  } else {
    BridgeNativeModulePerfLogger::moduleJSRequireBeginningEnd(name.c_str());
  }

  // If we've gotten this far, then we've signaled moduleJSRequireBeginningEnd
  //取出在modules_中的索引值。it 是指定module的一个键值对。
  size_t index = it->second;
  
  NativeModule *module = modules_[index].get();
  //以下就是把module 信息,存入到config
  // string name, object constants, array methodNames (methodId is index),
  // [array promiseMethodIds], [array syncMethodIds]
  folly::dynamic config = folly::dynamic::array(name);

  {
    SystraceSection s_("ModuleRegistry::getConstants", "module", name);
    /**
     * In the case that there are constants, we'll initialize the NativeModule,
     * and signal moduleJSRequireEndingStart. Otherwise, we'll simply signal the
     * event. The Module will be initialized when we invoke one of its
     * NativeModule methods.
     */
    config.push_back(module->getConstants());
  }

  {
    SystraceSection s_("ModuleRegistry::getMethods", "module", name);
    std::vector<MethodDescriptor> methods = module->getMethods();

    folly::dynamic methodNames = folly::dynamic::array;
    folly::dynamic promiseMethodIds = folly::dynamic::array;
    folly::dynamic syncMethodIds = folly::dynamic::array;

    for (auto &descriptor : methods) {
      // TODO: #10487027 compare tags instead of doing string comparison?
      methodNames.push_back(std::move(descriptor.name));
      if (descriptor.type == "promise") {
        promiseMethodIds.push_back(methodNames.size() - 1);
      } else if (descriptor.type == "sync") {
        syncMethodIds.push_back(methodNames.size() - 1);
      }
    }

    if (!methodNames.empty()) {
      config.push_back(std::move(methodNames));
      if (!promiseMethodIds.empty() || !syncMethodIds.empty()) {
        config.push_back(std::move(promiseMethodIds));
        if (!syncMethodIds.empty()) {
          config.push_back(std::move(syncMethodIds));
        }
      }
    }
  }

  ...
 return ModuleConfig{index, config};

}

代码回到2.4,继续往下执行,调用到js层

2.6 NativeModule # genModule

function genModule(
  config: ?ModuleConfig,
  moduleID: number,
): ?{
  name: string,
  module?: {...},
  ...
} {
  ...
  //这里的config,就是代码2.5的config
  const [moduleName, constants, methods, promiseMethods, syncMethods] = config;

  //在本节开头有提到,js->java通信方式的差异。
  //例如:ProxyJavaScriptExecutor这种的,会走到代码2.1 的genModule(config, moduleID),因为不需要在初始化,就把module所有方法进行解析,所以之传入moduleID。在后续通过loadModule来加载cofnig
  if (!constants && !methods) {
    // Module contents will be filled in lazily later
    return {name: moduleName};
  }

  const module = {};
  methods &&
    methods.forEach((methodName, methodID) => {
      //判断 调用是同步还是异步
      const isPromise = (promiseMethods && arrayContains(promiseMethods, methodID)) || false;
      const isSync = (syncMethods && arrayContains(syncMethods, methodID)) || false;
      const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
      //为每个方法,生成对应的js函数(区分同步和异步)。生成的方法,存入module,函数最后 返回它
      module[methodName] = genMethod(moduleID, methodID, methodType);
    });

  Object.assign(module, constants);
  ...
  return {name: moduleName, module};
}

接着到genMethod

2.7 NativeModule # genMethod

function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  //根据函数的类型,来生成不同的js函数,返回。待 NativeModules.xxxModuleName.xxxMethodName() 调用了具体的函数,才会执行
  if (type === 'promise') {
    fn = function promiseMethodWrapper(...args: Array<mixed>) {
      // In case we reject, capture a useful stack trace here.
      const enqueueingFrameError: ExtendedError = new Error();
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          args,
          data => resolve(data),
          errorData =>
            reject(
              updateErrorWithErrorData(
                (errorData: $FlowFixMe),
                enqueueingFrameError,
              ),
            ),
        );
      });
    };
  } else {
    fn = function nonPromiseMethodWrapper(...args: Array<mixed>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      // $FlowFixMe[incompatible-type]
      const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;
      // $FlowFixMe[incompatible-type]
      const onFail: ?(mixed) => void = hasErrorCallback ? secondLastArg : null;
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      const newArgs = args.slice(0, args.length - callbackCount);
      if (type === 'sync') {
        //同步调用
        return BatchedBridge.callNativeSyncHook(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      } else {
       //发送到js线程队列,是异步调用
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      }
    };
  }
  fn.type = type;
  return fn;
}

到此, NativeModules.xxxModuleName 的流程就结束了,后面调用函数,就是调用代码2.7 生成的函数,最终会调到,例如 BatchedBridge.enqueueNativeCall,下面来分析

2.8 MessageQueue # enqueueNativeCall

 enqueueNativeCall(
    moduleID: number,
    methodID: number,
    params: mixed[],
    onFail: ?(...mixed[]) => void,
    onSucc: ?(...mixed[]) => void,
  ) {
    this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
    //调用java的函数信息,存入_queue
    this._queue[MODULE_IDS].push(moduleID);
    this._queue[METHOD_IDS].push(methodID);

    ...省略dev的逻辑...
    
    this._queue[PARAMS].push(params);
    const now = Date.now();
    //如果5ms内有多个调用 则先待在队列里,防止过高频率的桥通信
    if (
      global.nativeFlushQueueImmediate &&
      now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS
    ) {
      const queue = this._queue;
      this._queue = [[], [], [], this._callID];
      this._lastFlush = now;
      //这个是调用到了c++,这个函数是在`JSIExecutor::initializeRuntime()`中设置的
      global.nativeFlushQueueImmediate(queue);
    }
    ...
   
  }

在上篇文章都有介绍 ,这里就不再看nativeFlushQueueImmediate 的赋值过程了,直接看它映射到的函数callNativeModules

2.9 JSIExecutor # callNativeModules

void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) {
  ...
  //delegate 就是 JsToNativeBridge类的对象,
  //在NativeToJsBridge::NativeToJsBridge的构造函数中 JsToNativeBridge 赋值为m_delegate、创建createJSExecutor时,传入参数m_delegate,也就是此处代码的delegate_
  delegate_->callNativeModules(
      *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}

2.10 JsToNativeBridge # callNativeModules

  void callNativeModules(
      __unused JSExecutor &executor,
      folly::dynamic &&calls,
      bool isEndOfBatch) override {

    m_batchHadNativeModuleOrTurboModuleCalls =
        m_batchHadNativeModuleOrTurboModuleCalls || !calls.empty();

    std::vector<MethodCall> methodCalls = parseMethodCalls(std::move(calls));
    BridgeNativeModulePerfLogger::asyncMethodCallBatchPreprocessEnd(
        (int)methodCalls.size());

    // An exception anywhere in here stops processing of the batch.  This
    // was the behavior of the Android bridge, and since exception handling
    // terminates the whole bridge, there's not much point in continuing.
    for (auto &call : methodCalls) {
     //m_registry 是 NativeToJsBridge::NativeToJsBridge的构造函数中传入的registry
     //也就是Instance::initializeBridge 的参数moduleRegistry,
     //也就是在 CatalystInstanceImpl::initializeBridge 中被创建的moduleRegistry_,类型是ModuleRegistry
      m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
    }
    //该变量,在java-js的结果,回调时js->java,这个值是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_batchHadNativeModuleOrTurboModuleCalls) {
        //在上篇文章,有介绍回调类 BridgeCallback 的使用
        m_callback->onBatchComplete();
        m_batchHadNativeModuleOrTurboModuleCalls = false;
      }
      m_callback->decrementPendingJSCalls();
    }
  }

下面来看看m_registry->callNativeMethod的调用

2.11 ModuleRegistry::callNativeMethod

void  ModuleRegistry::callNativeMethod(
    unsigned int moduleId,
    unsigned int methodId,
    folly::dynamic &&params,
    int callId) {
  //根据id 找到对应的module,这些module 就是在CatalystInstanceImpl::initializeBridge 参数中传入的
  modules_[moduleId]->invoke(methodId, std::move(params), callId);
}

你会不会有疑问,为什么这里根据moduleId,就能找到module。因为在代码2.5 的 ModuleRegistry::getConfig ,其实在modules_中找到指定name module的id

下面来继续分析invoke ,在CatalystInstanceImpl::initializeBridge 参数查看,知道了 module的类型是JavaModuleWrapper,跟随断点,来到JavaNativeModule::invoke

2.12 JavaModuleWrapper

void JavaNativeModule::invoke(
    unsigned int reactMethodId,
    folly::dynamic &&params,
    int callId) {
  //把调用作为runable 发送到native线程队列
  messageQueueThread_->runOnQueue(
      [this, reactMethodId, params = std::move(params), callId] {
        //获取 JavaModuleWrapper 的invoke函数,
        static auto invokeMethod =
            wrapper_->getClass()
                ->getMethod<void(jint, ReadableNativeArray::javaobject)>(
                    "invoke");
        //通过反射调用函数
        invokeMethod(
            wrapper_,
            static_cast<jint>(reactMethodId),
            ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
      });
}

看过上一篇的小伙伴,应该记得JMessageQueueThread ,messageQueueThread_类型就是JMessageQueueThread,它是通往java的一个类,runOnQueue 最终调用到的具体实现,是Java的MessageQueueThreadImpl的runOnQueue,发往Looper队列

public class MessageQueueThreadImpl implements MessageQueueThread {

  public void runOnQueue(Runnable runnable) {
    ...
    mHandler.post(runnable);
  }
}

invoke 函数最终会调用到 Java层的JavaModuleWrapper#invoke

2.13 JavaModuleWrapper#invoke

public class JavaModuleWrapper {
  ...
  public void invoke(int methodId, ReadableNativeArray parameters) {
    if (mMethods == null || methodId >= mMethods.size()) {
      return;
    }
   //见2.14
    mMethods.get(methodId).invoke(mJSInstance, parameters);
  }
}

2.14 JavaMethodWrapper#invoke

public class JavaMethodWrapper implements NativeModule.NativeMethod {

 @Override
  public void invoke(JSInstance jsInstance, ReadableArray parameters) {

    try {
      if (!mArgumentsProcessed) {
        processArguments();
      }
      ...

      int i = 0, jsArgumentsConsumed = 0;
      try {
        for (; i < mArgumentExtractors.length; i++) {
         //提取参数
          mArguments[i] =
              mArgumentExtractors[i].extractArgument(jsInstance, parameters, jsArgumentsConsumed);
          jsArgumentsConsumed += mArgumentExtractors[i].getJSArgumentsNeeded();
        }
      } catch (UnexpectedNativeTypeException e) {
        ...
      }

      try {
      // 在这里调用了java层 的目标函数
        mMethod.invoke(mModuleWrapper.getModule(), mArguments);
      } catch (IllegalArgumentException ie) {
        ...
    }
  }
}

至此,js->java的通信流程,就分析完了

按照我的国际惯例,欢迎小伙伴们 点赞、评论 支持一下,欢迎吐槽,U·ェ·U

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-04 17:24:58  更:2021-09-04 17:25:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 20:52:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计