Don't load native module support as part of the initial CS bundle
Reviewed By: javache Differential Revision: D4720386 fbshipit-source-id: cd8b6137aaff2d907adf089060bf7d356cd2f437
This commit is contained in:
parent
9344f3a95b
commit
6dc3a83e88
|
@ -361,7 +361,6 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
||||||
|
|
||||||
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
|
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
|
||||||
|
|
||||||
bindBridge();
|
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
|
@ -412,7 +411,6 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
||||||
evaluateScript(m_context, jsScript, jsSourceURL);
|
evaluateScript(m_context, jsScript, jsSourceURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bindBridge();
|
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
|
@ -428,24 +426,32 @@ void JSCExecutor::setJSModulesUnbundle(std::unique_ptr<JSModulesUnbundle> unbund
|
||||||
|
|
||||||
void JSCExecutor::bindBridge() throw(JSException) {
|
void JSCExecutor::bindBridge() throw(JSException) {
|
||||||
SystraceSection s("JSCExecutor::bindBridge");
|
SystraceSection s("JSCExecutor::bindBridge");
|
||||||
if (!m_delegate || !m_delegate->getModuleRegistry()) {
|
std::call_once(m_bindFlag, [this] {
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto global = Object::getGlobalObject(m_context);
|
auto global = Object::getGlobalObject(m_context);
|
||||||
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
|
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
|
||||||
|
if (batchedBridgeValue.isUndefined()) {
|
||||||
|
auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge");
|
||||||
|
if (!requireBatchedBridge.isUndefined()) {
|
||||||
|
batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
|
||||||
|
}
|
||||||
if (batchedBridgeValue.isUndefined()) {
|
if (batchedBridgeValue.isUndefined()) {
|
||||||
throwJSExecutionException("Could not get BatchedBridge, make sure your bundle is packaged correctly");
|
throwJSExecutionException("Could not get BatchedBridge, make sure your bundle is packaged correctly");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto batchedBridge = batchedBridgeValue.asObject();
|
auto batchedBridge = batchedBridgeValue.asObject();
|
||||||
m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
|
m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
|
||||||
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
|
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
|
||||||
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
|
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
|
||||||
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
|
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSCExecutor::callNativeModules(Value&& value) {
|
void JSCExecutor::callNativeModules(Value&& value) {
|
||||||
SystraceSection s("JSCExecutor::callNativeModules");
|
SystraceSection s("JSCExecutor::callNativeModules");
|
||||||
|
// If this fails, you need to pass a fully functional delegate with a
|
||||||
|
// module registry to the factory/ctor.
|
||||||
|
CHECK(m_delegate) << "Attempting to use native modules without a delegate";
|
||||||
try {
|
try {
|
||||||
auto calls = value.toJSONString();
|
auto calls = value.toJSONString();
|
||||||
m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
|
m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
|
||||||
|
@ -462,17 +468,31 @@ void JSCExecutor::callNativeModules(Value&& value) {
|
||||||
|
|
||||||
void JSCExecutor::flush() {
|
void JSCExecutor::flush() {
|
||||||
SystraceSection s("JSCExecutor::flush");
|
SystraceSection s("JSCExecutor::flush");
|
||||||
if (!m_delegate) {
|
|
||||||
// do nothing
|
if (m_flushedQueueJS) {
|
||||||
} else if (!m_delegate->getModuleRegistry()) {
|
|
||||||
callNativeModules(Value::makeNull(m_context));
|
|
||||||
} else {
|
|
||||||
// If this is failing, chances are you have provided a delegate with a
|
|
||||||
// module registry, but haven't loaded the JS which enables native function
|
|
||||||
// queueing. Add BatchedBridge.js to your bundle, pass a nullptr delegate,
|
|
||||||
// or make delegate->getModuleRegistry() return nullptr.
|
|
||||||
CHECK(m_flushedQueueJS) << "Attempting to use native methods without loading BatchedBridge.js";
|
|
||||||
callNativeModules(m_flushedQueueJS->callAsFunction({}));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,9 +503,9 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
|
||||||
|
|
||||||
auto result = [&] {
|
auto result = [&] {
|
||||||
try {
|
try {
|
||||||
// See flush()
|
if (!m_callFunctionReturnResultAndFlushedQueueJS) {
|
||||||
CHECK(m_callFunctionReturnFlushedQueueJS)
|
bindBridge();
|
||||||
<< "Attempting to call native methods without loading BatchedBridge.js";
|
}
|
||||||
return m_callFunctionReturnFlushedQueueJS->callAsFunction({
|
return m_callFunctionReturnFlushedQueueJS->callAsFunction({
|
||||||
Value(m_context, String::createExpectingAscii(m_context, moduleId)),
|
Value(m_context, String::createExpectingAscii(m_context, moduleId)),
|
||||||
Value(m_context, String::createExpectingAscii(m_context, methodId)),
|
Value(m_context, String::createExpectingAscii(m_context, methodId)),
|
||||||
|
@ -504,6 +524,9 @@ void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic&
|
||||||
SystraceSection s("JSCExecutor::invokeCallback");
|
SystraceSection s("JSCExecutor::invokeCallback");
|
||||||
auto result = [&] {
|
auto result = [&] {
|
||||||
try {
|
try {
|
||||||
|
if (!m_invokeCallbackAndReturnFlushedQueueJS) {
|
||||||
|
bindBridge();
|
||||||
|
}
|
||||||
return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction({
|
return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction({
|
||||||
Value::makeNumber(m_context, callbackId),
|
Value::makeNumber(m_context, callbackId),
|
||||||
Value::fromDynamic(m_context, std::move(arguments))
|
Value::fromDynamic(m_context, std::move(arguments))
|
||||||
|
@ -521,8 +544,9 @@ Value JSCExecutor::callFunctionSyncWithValue(
|
||||||
const std::string& module, const std::string& method, Value args) {
|
const std::string& module, const std::string& method, Value args) {
|
||||||
SystraceSection s("JSCExecutor::callFunction");
|
SystraceSection s("JSCExecutor::callFunction");
|
||||||
|
|
||||||
// See flush()
|
if (!m_callFunctionReturnResultAndFlushedQueueJS) {
|
||||||
CHECK(m_callFunctionReturnResultAndFlushedQueueJS);
|
bindBridge();
|
||||||
|
}
|
||||||
Object result = m_callFunctionReturnResultAndFlushedQueueJS->callAsFunction({
|
Object result = m_callFunctionReturnResultAndFlushedQueueJS->callAsFunction({
|
||||||
Value(m_context, String::createExpectingAscii(m_context, module)),
|
Value(m_context, String::createExpectingAscii(m_context, module)),
|
||||||
Value(m_context, String::createExpectingAscii(m_context, method)),
|
Value(m_context, String::createExpectingAscii(m_context, method)),
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <cxxreact/Executor.h>
|
#include <cxxreact/Executor.h>
|
||||||
|
@ -112,6 +113,7 @@ private:
|
||||||
std::unique_ptr<JSModulesUnbundle> m_unbundle;
|
std::unique_ptr<JSModulesUnbundle> m_unbundle;
|
||||||
JSCNativeModules m_nativeModules;
|
JSCNativeModules m_nativeModules;
|
||||||
folly::dynamic m_jscConfig;
|
folly::dynamic m_jscConfig;
|
||||||
|
std::once_flag m_bindFlag;
|
||||||
|
|
||||||
folly::Optional<Object> m_invokeCallbackAndReturnFlushedQueueJS;
|
folly::Optional<Object> m_invokeCallbackAndReturnFlushedQueueJS;
|
||||||
folly::Optional<Object> m_callFunctionReturnFlushedQueueJS;
|
folly::Optional<Object> m_callFunctionReturnFlushedQueueJS;
|
||||||
|
|
|
@ -237,6 +237,13 @@ public:
|
||||||
Value(JSContextRef context, JSStringRef value);
|
Value(JSContextRef context, JSStringRef value);
|
||||||
Value(Value&&);
|
Value(Value&&);
|
||||||
|
|
||||||
|
Value& operator=(Value&& other) {
|
||||||
|
m_context = other.m_context;
|
||||||
|
m_value = other.m_value;
|
||||||
|
other.m_value = NULL;
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
operator JSValueRef() const {
|
operator JSValueRef() const {
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue