ReactNative 통신 메커니즘c++ 엔 드 소스 분석
ReactNative 시작 과정 소스 코드 분석 ReactNative 통신 메커니즘자바 엔 드 소스 분석 ReactNative 통신 메커니즘c++ 엔 드 소스 분석 ReactNative 통신 메커니즘js 엔 드 소스 분석
지난 장 에서 우 리 는 자바 엔 드 통신 메커니즘 절 차 를 분 석 했 는데 이 장 에서 우 리 는 c + 엔 드 호출 절 차 를 분석 했다.
CatalystInstanceImpl.cpp
Catalyst InstanceImpl. 자바 류 에 대응 하여 자바 엔 드 native 방법의 구체 적 인 실현 입 니 다.
void CatalystInstanceImpl::initializeBridge(
jni::alias_ref<:javaobject> callback,
// This executor is actually a factory holder.
JavaScriptExecutorHolder* jseh,
jni::alias_ref<:javaobject> jsQueue,
jni::alias_ref<:javaobject> nativeModulesQueue,
jni::alias_ref<:javaobject> uiBackgroundQueue,
jni::alias_ref
<:jcollection>::javaobject> javaModules,
jni::alias_ref
<:jcollection>::javaobject> cxxModules) {
moduleMessageQueue_ = std::make_shared(nativeModulesQueue);
if (uiBackgroundQueue.get() != nullptr) {
uiBackgroundMessageQueue_ =
std::make_shared(uiBackgroundQueue);
}
moduleRegistry_ = std::make_shared(
buildNativeModuleList(
std::weak_ptr(instance_),
javaModules,
cxxModules,
moduleMessageQueue_,
uiBackgroundMessageQueue_));
instance_->initializeBridge(
folly::make_unique(
callback,
uiBackgroundMessageQueue_ !=
NULL ? uiBackgroundMessageQueue_ : moduleMessageQueue_),
jseh->getExecutorFactory(),
folly::make_unique(jsQueue),
moduleRegistry_);
}
void CatalystInstanceImpl::jniCallJSFunction(std::string module,
std::string method, NativeArray* arguments) {
instance_->callJSFunction(std::move(module),
std::move(method),
arguments->consume());
}
그냥 리 턴 instance대응 방법.
void CatalystInstanceImpl::jniCallJSCallback(jint callbackId,
NativeArray* arguments) {
instance_->callJSCallback(callbackId, arguments->consume());
}
마찬가지 로 반전 instance대응 방법.
ModuleRegistry.cpp
NativeModule. cpp 목록 modules 저장,자바 엔 드 를 되 돌 리 는 NativeModule 방법 입 니 다.
folly::Optional ModuleRegistry::getConfig(const std::string& name) {
``````
}
주로 NativeModule 의 방법 명 목록 과 상수 목록 을 얻어 js 단 NativeModules. js 에 전달 합 니 다.
void ModuleRegistry::callNativeMethod(unsigned int moduleId,
unsigned int methodId, folly::dynamic&& params, int callId) {
if (moduleId >= modules_.size()) {
throw std::runtime_error(
folly::to<:string>("moduleId ", moduleId,
" out of range [0..", modules_.size(), ")"));
}
modules_[moduleId]->invoke(methodId, std::move(params), callId);
}
비동기 NativeModule 방법의 호출자바 모듈 러 Wrapper. cpp 의 invoke 방법 을 호출 하면 자바 모듈 러 Wrapper. 자바 의 invoke 방법 을 호출 합 니 다.
MethodCallResult ModuleRegistry::callSerializableNativeHook(unsigned int moduleId,
unsigned int methodId, folly::dynamic&& params) {
if (moduleId >= modules_.size()) {
throw std::runtime_error(
folly::to<:string>("moduleId ", moduleId,
"out of range [0..", modules_.size(), ")"));
}
return modules_[moduleId]->
callSerializableNativeHook(methodId, std::move(params));
}
NativeModule 방법의 호출 을 동기 화 합 니 다.자바 모듈 러 Wrapper. cpp 의 callSerializable NativeHook 방법 을 호출 합 니 다. 이 방법 은 NativeModule 방법 을 직접 호출 하여 결과 값 을 얻 고 되 돌려 줍 니 다.
JavaModuleWrapper.cpp
void JavaNativeModule::invoke(unsigned int reactMethodId,
folly::dynamic&& params, int callId) {
messageQueueThread_->runOnQueue(
[this, reactMethodId, params=std::move(params), callId] {
static auto invokeMethod = wrapper_->getClass()->getMethod
("invoke");
#ifdef WITH_FBSYSTRACE
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#endif
invokeMethod(
wrapper_,
static_cast(reactMethodId),
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
});
}
이 방법 은 주로 자바 모듈 러 Wrapper. 자바 의 invoke 방법 을 호출 합 니 다.wrapper_자바 모듈 러 Wrapper. 자바 에 대응 하 는 실례 입 니 다.
MethodCallResult JavaNativeModule::callSerializableNativeHook(
unsigned int reactMethodId, folly::dynamic&& params) {
// TODO: evaluate whether calling through invoke is potentially faster
if (reactMethodId >= syncMethods_.size()) {
throw std::invalid_argument(
folly::to<:string>("methodId ", reactMethodId,
" out of range [0..", syncMethods_.size(), "]"));
}
auto& method = syncMethods_[reactMethodId];
CHECK(method.hasValue() && method->isSyncHook())
<< "Trying to invoke a asynchronous method as synchronous hook";
return method->invoke(instance_, wrapper_->getModule(), params);
}
NativeModule 방법 을 직접 호출 하고 결과 값 을 되 돌려 줍 니 다.
Instance.cpp
주요 역할 은 Catalyst InstanceImpl 에 대응 하 는 방법 을 처리 하고 NativeToJSBridge 인 스 턴 스 를 만 드 는 것 입 니 다.
void Instance::initializeBridge(
std::unique_ptr callback,
std::shared_ptr jsef,
std::shared_ptr jsQueue,
std::shared_ptr moduleRegistry) {
callback_ = std::move(callback);
moduleRegistry_ = std::move(moduleRegistry);
jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
nativeToJsBridge_ = folly::make_unique(
jsef.get(), moduleRegistry_, jsQueue, callback_);
std::lock_guard<:mutex> lock(m_syncMutex);
m_syncReady = true;
m_syncCV.notify_all();
});
CHECK(nativeToJsBridge_);
}
속성 값 을 할당 하고 NativeToJSBridge 인 스 턴 스 를 만 듭 니 다.callback_자바 엔 드 ReactCallback 의 인 스 턴 스 입 니 다. jsef 는 JSCExecutor. 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));
}
먼저 자바 엔 드 ReactCallback 의 increment PendingJScalls 방법 을 바 꾼 다음 nativeToJs Bridge 를 호출 합 니 다.의 대응 방법.
void Instance::callJSCallback(uint64_t callbackId, folly::dynamic &¶ms) {
SystraceSection s("Instance::callJSCallback");
callback_->incrementPendingJSCalls();
nativeToJsBridge_->invokeCallback((double)callbackId, std::move(params));
}
먼저 자바 엔 드 ReactCallback 의 increment PendingJScalls 방법 을 바 꾼 다음 nativeToJs Bridge 를 호출 합 니 다.의 대응 방법.
NativeToJsBridge.cpp
JSToNativeBridge 인 스 턴 스 와 JSexecutor 인 스 턴 스 (즉 JSCExecutor. cpp 인 스 턴 스) 를 만 든 다음 JSexecutor 대응 방법 으로 js 와 상호작용 합 니 다.이 클래스 는 JsToNativeBridge 클래스 도 포함 되 어 있 습 니 다. 자바 엔 드 와 상호작용 을 하 는 것, 즉 NativeModule 을 호출 하 는 것 입 니 다. 모든 모듈 레지스터 리 를 가지 고 있 습 니 다.
JsToNativeBridge
JsToNativeBridge(std::shared_ptr registry,
std::shared_ptr callback)
: m_registry(registry)
, m_callback(callback) {}
모듈 레지스터 리 속성 을 가 져 옵 니 다.콜백 은 자바 엔 드 의 BridgeCallback 인 스 턴 스 입 니 다.
void callNativeModules(
JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
CHECK(m_registry || calls.empty()) <<
"native module calls cannot be completed with no native modules";
m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();
for (auto& call : parseMethodCalls(std::move(calls))) {
m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
if (isEndOfBatch) {
if (m_batchHadNativeModuleCalls) {
m_callback->onBatchComplete();
m_batchHadNativeModuleCalls = false;
}
m_callback->decrementPendingJSCalls();
}
}
우 리 는 m 를 통 해registry 의 callNativeMethod 방법 은 자바 단 에 대응 하 는 비동기 방법 을 되 돌려 줍 니 다.parseMethodCalls 는 MethodCall. cpp 의 방법 으로 js 단 에서 전 달 된 json 형식 데 이 터 를 우리 가 필요 로 하 는 데이터 형식 으로 변환 하 는 것 이 주요 역할 을 합 니 다.
MethodCallResult callSerializableNativeHook(
JSExecutor& executor, unsigned int moduleId, unsigned int methodId,
folly::dynamic&& args) override {
return m_registry->callSerializableNativeHook(moduleId, methodId, std::move(args));
}
통과 mregistry 의 callSerializable NativeHook 은 NativeModule 동기 화 방법 을 호출 합 니 다.
다음은 NativeToJSBridge 의 방법 입 니 다.
NativeToJsBridge::NativeToJsBridge(
JSExecutorFactory* jsExecutorFactory,
std::shared_ptr registry,
std::shared_ptr jsQueue,
std::shared_ptr callback)
: m_destroyed(std::make_shared(false))
, m_delegate(std::make_shared(registry, callback))
, m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue))
, m_executorMessageQueueThread(std::move(jsQueue)) {}
JSToNativeBridge 인 스 턴 스 m 을 만 든 것 을 볼 수 있 습 니 다.delegate, 그리고 JSexecutor 인 스 턴 스 mexecutor (즉 JSCExecutor. 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([module = std::move(module), method = std::move(method),
arguments = std::move(arguments), systraceCookie]
(JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
"JSCall",
systraceCookie);
SystraceSection s("NativeToJsBridge::callFunction",
"module", module, "method", method);
#endif
executor->callFunction(module, method, arguments);
});
}
JSexecutor 의 callFunction 방법 을 사용 합 니 다.
void NativeToJsBridge::invokeCallback(double callbackId,
folly::dynamic&& arguments) {
int systraceCookie = -1;
#ifdef WITH_FBSYSTRACE
systraceCookie = m_systraceCookie++;
FbSystraceAsyncFlow::begin(
TRACE_TAG_REACT_CXX_BRIDGE,
"",
systraceCookie);
#endif
runOnExecutorQueue(
[callbackId, arguments = std::move(arguments), systraceCookie]
(JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
"",
systraceCookie);
SystraceSection s("NativeToJsBridge::invokeCallback");
#endif
executor->invokeCallback(callbackId, arguments);
});
}
JSexecutor 의 invokeCallback 방법 (JSC Executor. cpp 에서 구체 적 으로 구현) 을 사용 합 니 다.
JSCExecutor.cpp
진짜 js 단 에서 상호작용 을 하고 js 단 을 직접 호출 하 는 방법 입 니 다.
std::unique_ptr JSCExecutorFactory::createJSExecutor(
std::shared_ptr delegate,
std::shared_ptr jsQueue) {
return folly::make_unique(delegate, jsQueue, m_jscConfig);
}
JSexecutor 인 스 턴 스 를 만 들 고 JSToNativeBridge 인 스 턴 스 대상 delegate 를 가지 고 자바 엔 드 방법 을 되 돌 릴 수 있 습 니 다.
void JSCExecutor::bindBridge() throw(JSException) {
SystraceSection s("JSCExecutor::bindBridge");
std::call_once(m_bindFlag, [this] {
auto global = Object::getGlobalObject(m_context);
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");
}
}
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 엔 드 의 인 스 턴 스 대상 과 방법 을 얻 고 js 엔 드 코드 를 직접 호출 합 니 다. 'fbBatched Bridge ': Batched Bridge. js 에서 정 의 된 것 입 니 다. 사실은 Message Queue. js 대상 인 스 턴 스 입 니 다. 네 가지 방법 을 참조 하여 js 방법 을 직접 호출 합 니 다.
void JSCExecutor::callFunction(const std::string& moduleId,
const std::string& methodId, const folly::dynamic& arguments) {
SystraceSection s("JSCExecutor::callFunction");
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));
}
이 방법 은 js 단 JavaScriptModule 대응 방법 을 호출 하고 현재 js 단 에서 시작 하 는 NativeModule 비동기 방법 요청 목록 을 얻 은 다음 에 callNativeModules 방법 을 호출 합 니 다. 이 방법 은 JsToNativeBridge 의 callNativeModules 방법 을 호출 하여 자바 단 코드 를 호출 합 니 다.
void JSCExecutor::invokeCallback(const double callbackId,
const folly::dynamic& arguments) {
SystraceSection s("JSCExecutor::invokeCallback");
auto result = [&] {
JSContextLock lock(m_context);
try {
if (!m_invokeCallbackAndReturnFlushedQueueJS) {
bindBridge();
}
return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction({
Value::makeNumber(m_context, callbackId),
Value::fromDynamic(m_context, std::move(arguments))
});
} catch (...) {
std::throw_with_nested(
std::runtime_error(folly::to<:string>("Error invoking callback ",
callbackId)));
}
}();
callNativeModules(std::move(result));
}
이전 방법 과 마찬가지 로 js 단 대응 방법 을 호출 하여 현재 js 단 에서 시 작 된 NativeModule 비동기 방법 요청 목록 을 얻 고 callNativeModules 방법 을 호출 합 니 다.
void JSCExecutor::callNativeModules(Value&& value) {
SystraceSection s("JSCExecutor::callNativeModules");
CHECK(m_delegate) << "Attempting to use native modules without a delegate";
try {
auto calls = value.toJSONString();
m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
} catch (...) {
std::string message = "Error in callNativeModules()";
try {
message += ":" + value.toString().str();
} catch (...) {
// ignored
}
std::throw_with_nested(std::runtime_error(message));
}
}
Js ToNative Bridge 의 callNative Modules 방법 을 호출 합 니 다.
JSValueRef JSCExecutor::nativeCallSyncHook(
size_t argumentCount,
const JSValueRef arguments[]) {
if (argumentCount != 3) {
throw std::invalid_argument("Got wrong number of args");
}
unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger();
unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger();
folly::dynamic args =
folly::parseJson(Value(m_context, arguments[2]).toJSONString());
if (!args.isArray()) {
throw std::invalid_argument(
folly::to<:string>(
"method parameters should be array, but are ", args.typeName()));
}
MethodCallResult result = m_delegate->callSerializableNativeHook(
*this,
moduleId,
methodId,
std::move(args));
if (!result.hasValue()) {
return Value::makeUndefined(m_context);
}
return Value::fromDynamic(m_context, result.value());
}
이 방법 은 js 단 NativeModules. js 에서 호출 되 며, js 단 에서 NativeModule 의 동기 화 방법 을 호출 할 때 이 방법 으로 호출 됩 니 다.
JsToNativeBridge -> callSerializableNativeHook 방법 을 호출 한 다음 ModuleRegistry -> callSerializableNativeHook 방법 을 호출 하여 자바 모듈 러 Wrapper -> callSerializableNativeHook 방법 을 계속 호출 합 니 다. 이 방법 은 자바 엔 드 NativeModule 대응 방법 을 직접 호출 하고 결과 값 을 되 돌려 줍 니 다.(자바 모듈 러 Wrapper. java 와 자바 MethodWrapper. java 의 invoke 방법 을 호출 하지 않 았 습 니 다. 리 셋 방법 으로 js 단 에 결과 값 을 전달 하기 때문에 결과 값 을 직접 되 돌 릴 수 없습니다.)
자바 와 c++ 코드 의 상호 호출, js 와 c + 코드 의 상호 호출 에 대해 말씀 드 리 겠 습 니 다. 자바 가 jni 를 통 해 c++ 엔 드 코드 와 의 상호 호출 을 실현 할 수 있다 는 것 을 잘 알 고 있 습 니 다. 그러면 js 는 어떻게 이 루어 집 니까? 전역 변수 global, c + global 을 통 해 js 엔 드 의 인 스 턴 스 와 방법 을 얻 을 수 있 고 global 전역 변수 에 c + 로 컬 방법 을 등록 할 수 있 습 니 다. 그리고 js 엔 드 는global 에서 c++ 방법 을 호출 합 니 다. 예 를 들 어 installNativeHook ("nativeCallSyncHook") 은 전역 변수 에 nativeCallSyncHook 이라는 로 컬 방법 을 등록 하 는 것 입 니 다.
총결산
자바 엔 드 -> js 엔 드:
CatalystInstanceImpl. cpp 부터 Instance. cpp 대응 방법 을 호출 하고 NativeToJs Bridge. cpp 대응 방법 을 호출 한 다음 에 JScExecutor. cpp 대응 방법 을 호출 합 니 다. 최종 적 으로 JScExecutor 에서 js 단 방법 을 호출 합 니 다 (JScExecutor 가 js 대상 방법 을 가지 고 있 기 때 문 입 니 다)
js 단 -> 자바 단:
이 장 은 c++ 단 통신 프로 세 스 의 소스 코드 를 분 석 했 습 니 다. 그러면 다음 장 은 js 단의 통신 체제 의 소스 코드 를 분석 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.