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 &&params) {

  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获取的对象了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容