React Native java调用js源码分析

RN若要调用js,先通过

(mReactContext.getJSModule(NativeToJsBridge.class)得到Js模块。

这一步最后调用的是com.facebook.react.bridge.JavaScriptModuleRegistry#getJavaScriptModule

实际上,这个函数里面是new了一个代理对象

JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(

    moduleInterface.getClassLoader(),

    new Class[]{moduleInterface},

    new JavaScriptModuleInvocationHandler(instance, moduleInterface));

当调用代理对象对应js方法的时候,走到

com.facebook.react.bridge.JavaScriptModuleRegistry.JavaScriptModuleInvocationHandler#invoke:(这个过程是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;

}

  mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);这一句调用的是:

com.facebook.react.bridge.CatalystInstanceImpl#callFunction(com.facebook.react.bridge.CatalystInstanceImpl.PendingJSCall)

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;

  }

  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);

}

  function.call(this);也就是:

com.facebook.react.bridge.CatalystInstanceImpl.PendingJSCall#call

void call(CatalystInstanceImpl catalystInstance) {

  NativeArray arguments = mArguments != null ? mArguments : new WritableNativeArray();

  catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);

}

最后调用到了jni:catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);

该jni函数在:

ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp:

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());

}

 instance_->callJSFunctio   这一句调用的是:

ReactCommon/cxxreact/Instance.cpp:

void Instance::callJSFunction(std::string &&module, std::string &&method,

                              folly::dynamic &¶ms) {

  callback_->incrementPendingJSCalls();

  nativeToJsBridge_->callFunction(std::move(module), std::move(method),

                                  std::move(params));

}

nativeToJsBridge_->callFunction 这一句是:

ReactCommon/cxxreact/NativeToJsBridge.cpp:

void NativeToJsBridge::callFunction(

    std::string&& module,

    std::string&& method,

    folly::dynamic&& arguments) {

  int systraceCookie = -1;

  #ifdef WITH_FBSYSTRACE

  systraceCookie = m_systraceCookie++;

  FbSystraceAsyncFlow::begin(

      TRACE_TAG_REACT_CXX_BRIDGE,

      "JSCall",

      systraceCookie);

  #endif

  runOnExecutorQueue([this, module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie]

    (JSExecutor* executor) {

      if (m_applicationScriptHasFailure) {

        LOG(ERROR) << "Attempting to call JS function on a bad application bundle: " << module.c_str() << "." << method.c_str() << "()";

        throw std::runtime_error("Attempting to call JS function on a bad application bundle: " + module + "." + method + "()");

      }

      #ifdef WITH_FBSYSTRACE

      FbSystraceAsyncFlow::end(

          TRACE_TAG_REACT_CXX_BRIDGE,

          "JSCall",

          systraceCookie);

      SystraceSection s("NativeToJsBridge::callFunction", "module", module, "method", method);

      #endif

      // 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->callFunction(module, method, arguments);

    });

}

 executor->callFunction 实际上调用的是:

ReactCommon/cxxreact/JSCExecutor.cpp

void JSCExecutor::callFunction(

    const std::string& moduleId,

    const std::string& methodId,

    const folly::dynamic& arguments) {

  SystraceSection s("JSCExecutor::callFunction");

  // This weird pattern is because Value is not default constructible.

  // The lambda is inlined, so there's no overhead.

  auto result = [&] {

    JSContextLock lock(m_context);

    try {

      if (!m_callFunctionReturnResultAndFlushedQueueJS) {

        bindBridge();

      }

      return m_callFunctionReturnFlushedQueueJS->callAsFunction(

          {Value(m_context, String::createExpectingAscii(m_context, moduleId)),

          Value(m_context, String::createExpectingAscii(m_context, methodId)),

          Value::fromDynamic(m_context, std::move(arguments))});

    } catch (...) {

      std::throw_with_nested(

          std::runtime_error("Error calling " + moduleId + "." + methodId));

    }

  }();

  callNativeModules(std::move(result));

}

到这里基本就结束了,通过m_callFunctionReturnFlushedQueueJS->callAsFunction来执行js函数。

我们顺便跟一下m_callFunctionReturnFlushedQueueJS是怎么来的

m_callFunctionReturnFlushedQueueJS->callAsFunction(

    {Value(m_context, String::createExpectingAscii(m_context, moduleId)),

    Value(m_context, String::createExpectingAscii(m_context, methodId)),

    Value::fromDynamic(m_context, std::move(arguments))});

这一句的m_callFunctionReturnFlushedQueueJS是:

m_callFunctionReturnFlushedQueueJS =

    batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();

这个就是操作Js对象了。

上面的batchedBridge来自batchedBridgeValue:

auto batchedBridge = batchedBridgeValue.asObject();

而batchedBridgeValue是:

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");

  }

这里的global是:

auto global = Object::getGlobalObject(m_context);

而m_context是:

m_context =

    JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass);

JSC_JSGlobalContextCreateInGroup这个是:

#define JSC_JSGlobalContextCreateInGroup(...) __jsc_bool_wrapper(JSGlobalContextCreateInGroup, __VA_ARGS__)


从这里就可以看到m_context是通过jscore的api:JSGlobalContextCreateInGroup获取的对象了。

你可能感兴趣的:(React Native java调用js源码分析)