Support ModuleHolder-based lazy init of C++ modules with C++ bridge on android
Reviewed By: AaaChiuuu Differential Revision: D4614479 fbshipit-source-id: 109ac34b8688f0113675e4a4479d1ddcc6169ed4
This commit is contained in:
parent
6410e256c5
commit
e622d51e20
|
@ -553,7 +553,8 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||||
}
|
}
|
||||||
modules.emplace_back(
|
modules.emplace_back(
|
||||||
new QueueNativeModule(self, std::make_unique<CxxNativeModule>(
|
new QueueNativeModule(self, std::make_unique<CxxNativeModule>(
|
||||||
_reactInstance, [(RCTCxxModule *)(moduleData.instance) move])));
|
_reactInstance, [moduleData.name UTF8String],
|
||||||
|
[moduleData] { return [(RCTCxxModule *)(moduleData.instance) move]; })));
|
||||||
} else {
|
} else {
|
||||||
modules.emplace_back(new RCTNativeModule(self, moduleData));
|
modules.emplace_back(new RCTNativeModule(self, moduleData));
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
final JavaScriptModuleRegistry jsModuleRegistry,
|
final JavaScriptModuleRegistry jsModuleRegistry,
|
||||||
final JSBundleLoader jsBundleLoader,
|
final JSBundleLoader jsBundleLoader,
|
||||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||||
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
||||||
mHybridData = initHybrid();
|
mHybridData = initHybrid();
|
||||||
|
|
||||||
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
|
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
|
||||||
|
@ -123,6 +123,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||||
mTraceListener = new JSProfilerTraceListener(this);
|
mTraceListener = new JSProfilerTraceListener(this);
|
||||||
|
|
||||||
|
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
|
||||||
initializeBridge(
|
initializeBridge(
|
||||||
new BridgeCallback(this),
|
new BridgeCallback(this),
|
||||||
jsExecutor,
|
jsExecutor,
|
||||||
|
@ -130,6 +131,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
mReactQueueConfiguration.getNativeModulesQueueThread(),
|
mReactQueueConfiguration.getNativeModulesQueueThread(),
|
||||||
mJavaRegistry.getJavaModules(this),
|
mJavaRegistry.getJavaModules(this),
|
||||||
mJavaRegistry.getCxxModules());
|
mJavaRegistry.getCxxModules());
|
||||||
|
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
|
||||||
mMainExecutorToken = getMainExecutorToken();
|
mMainExecutorToken = getMainExecutorToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +184,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
MessageQueueThread jsQueue,
|
MessageQueueThread jsQueue,
|
||||||
MessageQueueThread moduleQueue,
|
MessageQueueThread moduleQueue,
|
||||||
Collection<JavaModuleWrapper> javaModules,
|
Collection<JavaModuleWrapper> javaModules,
|
||||||
Collection<CxxModuleWrapper> cxxModules);
|
Collection<ModuleHolder> cxxModules);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This API is used in situations where the JS bundle is being executed not on
|
* This API is used in situations where the JS bundle is being executed not on
|
||||||
|
|
|
@ -53,12 +53,12 @@ public class NativeModuleRegistry {
|
||||||
return javaModules;
|
return javaModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Collection<CxxModuleWrapper> getCxxModules() {
|
/* package */ Collection<ModuleHolder> getCxxModules() {
|
||||||
ArrayList<CxxModuleWrapper> cxxModules = new ArrayList<>();
|
ArrayList<ModuleHolder> cxxModules = new ArrayList<>();
|
||||||
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
|
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
|
||||||
Class<?> type = entry.getKey();
|
Class<?> type = entry.getKey();
|
||||||
if (CxxModuleWrapper.class.isAssignableFrom(type)) {
|
if (CxxModuleWrapper.class.isAssignableFrom(type)) {
|
||||||
cxxModules.add((CxxModuleWrapper) entry.getValue().getModule());
|
cxxModules.add(entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cxxModules;
|
return cxxModules;
|
||||||
|
|
|
@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \
|
||||||
JSLogging.cpp \
|
JSLogging.cpp \
|
||||||
JniJSModulesUnbundle.cpp \
|
JniJSModulesUnbundle.cpp \
|
||||||
MethodInvoker.cpp \
|
MethodInvoker.cpp \
|
||||||
|
ModuleRegistryBuilder.cpp \
|
||||||
NativeArray.cpp \
|
NativeArray.cpp \
|
||||||
NativeCommon.cpp \
|
NativeCommon.cpp \
|
||||||
NativeMap.cpp \
|
NativeMap.cpp \
|
||||||
|
|
|
@ -6,6 +6,7 @@ EXPORTED_HEADERS = [
|
||||||
"JExecutorToken.h",
|
"JExecutorToken.h",
|
||||||
"JSLoader.h",
|
"JSLoader.h",
|
||||||
"MethodInvoker.h",
|
"MethodInvoker.h",
|
||||||
|
"ModuleRegistryBuilder.h",
|
||||||
"NativeArray.h",
|
"NativeArray.h",
|
||||||
"NativeCommon.h",
|
"NativeCommon.h",
|
||||||
"NativeMap.h",
|
"NativeMap.h",
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <cxxreact/ModuleRegistry.h>
|
#include <cxxreact/ModuleRegistry.h>
|
||||||
#include <cxxreact/CxxNativeModule.h>
|
#include <cxxreact/CxxNativeModule.h>
|
||||||
|
|
||||||
|
#include "CxxModuleWrapper.h"
|
||||||
#include "JavaScriptExecutorHolder.h"
|
#include "JavaScriptExecutorHolder.h"
|
||||||
#include "JniJSModulesUnbundle.h"
|
#include "JniJSModulesUnbundle.h"
|
||||||
#include "JNativeRunnable.h"
|
#include "JNativeRunnable.h"
|
||||||
|
@ -128,21 +129,10 @@ void CatalystInstanceImpl::initializeBridge(
|
||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
||||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||||
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules) {
|
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
|
||||||
// TODO mhorowitz: how to assert here?
|
// TODO mhorowitz: how to assert here?
|
||||||
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
|
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
|
||||||
|
|
||||||
std::vector<std::unique_ptr<NativeModule>> modules;
|
|
||||||
std::weak_ptr<Instance> winstance(instance_);
|
|
||||||
for (const auto& jm : *javaModules) {
|
|
||||||
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
|
|
||||||
}
|
|
||||||
for (const auto& cm : *cxxModules) {
|
|
||||||
modules.emplace_back(
|
|
||||||
folly::make_unique<CxxNativeModule>(winstance, std::move(cthis(cm)->getModule())));
|
|
||||||
}
|
|
||||||
auto moduleRegistry = std::make_shared<ModuleRegistry>(std::move(modules));
|
|
||||||
|
|
||||||
// This used to be:
|
// This used to be:
|
||||||
//
|
//
|
||||||
// Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> Bridge::Callback
|
// Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> Bridge::Callback
|
||||||
|
@ -163,7 +153,8 @@ void CatalystInstanceImpl::initializeBridge(
|
||||||
jseh->getExecutorFactory(),
|
jseh->getExecutorFactory(),
|
||||||
folly::make_unique<JMessageQueueThread>(jsQueue),
|
folly::make_unique<JMessageQueueThread>(jsQueue),
|
||||||
folly::make_unique<JMessageQueueThread>(moduleQueue),
|
folly::make_unique<JMessageQueueThread>(moduleQueue),
|
||||||
moduleRegistry);
|
buildModuleRegistry(std::weak_ptr<Instance>(instance_),
|
||||||
|
javaModules, cxxModules));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {
|
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "JMessageQueueThread.h"
|
#include "JMessageQueueThread.h"
|
||||||
#include "JSLoader.h"
|
#include "JSLoader.h"
|
||||||
#include "JavaModuleWrapper.h"
|
#include "JavaModuleWrapper.h"
|
||||||
|
#include "ModuleRegistryBuilder.h"
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
|
@ -48,7 +49,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
|
||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
||||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||||
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules);
|
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the source URL of the underlying bridge without loading any JS code.
|
* Sets the source URL of the underlying bridge without loading any JS code.
|
||||||
|
|
|
@ -12,7 +12,13 @@
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
|
|
||||||
class CxxModuleWrapper : public jni::HybridClass<CxxModuleWrapper> {
|
struct JNativeModule : jni::JavaClass<JNativeModule> {
|
||||||
|
constexpr static const char *const kJavaDescriptor =
|
||||||
|
"Lcom/facebook/react/bridge/NativeModule;";
|
||||||
|
};
|
||||||
|
|
||||||
|
class CxxModuleWrapper :
|
||||||
|
public jni::HybridClass<CxxModuleWrapper, JNativeModule> {
|
||||||
public:
|
public:
|
||||||
constexpr static const char *const kJavaDescriptor =
|
constexpr static const char *const kJavaDescriptor =
|
||||||
"Lcom/facebook/react/cxxbridge/CxxModuleWrapper;";
|
"Lcom/facebook/react/cxxbridge/CxxModuleWrapper;";
|
||||||
|
|
|
@ -27,6 +27,8 @@ struct JavaModuleWrapper : jni::JavaClass<JavaModuleWrapper> {
|
||||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/JavaModuleWrapper;";
|
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/JavaModuleWrapper;";
|
||||||
|
|
||||||
jni::local_ref<JBaseJavaModule::javaobject> getModule() {
|
jni::local_ref<JBaseJavaModule::javaobject> getModule() {
|
||||||
|
// This is the call which causes a lazy Java module to actually be
|
||||||
|
// created.
|
||||||
static auto getModule = javaClassStatic()->getMethod<JBaseJavaModule::javaobject()>("getModule");
|
static auto getModule = javaClassStatic()->getMethod<JBaseJavaModule::javaobject()>("getModule");
|
||||||
return getModule(self());
|
return getModule(self());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "ModuleRegistryBuilder.h"
|
||||||
|
|
||||||
|
#include <cxxreact/CxxNativeModule.h>
|
||||||
|
#include <folly/Memory.h>
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
std::string ModuleHolder::getName() const {
|
||||||
|
static auto method = getClass()->getMethod<jstring()>("getName");
|
||||||
|
return method(self())->toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
xplat::module::CxxModule::Provider ModuleHolder::getProvider() const {
|
||||||
|
return [self=jni::make_global(self())] {
|
||||||
|
static auto method =
|
||||||
|
ModuleHolder::javaClassStatic()->getMethod<JNativeModule::javaobject()>(
|
||||||
|
"getModule");
|
||||||
|
// This is the call which uses the lazy Java Provider to instantiate the
|
||||||
|
// Java CxxModuleWrapper which contains the CxxModule.
|
||||||
|
auto module = method(self);
|
||||||
|
CHECK(module->isInstanceOf(CxxModuleWrapper::javaClassStatic()))
|
||||||
|
<< "module isn't a C++ module";
|
||||||
|
auto cxxModule = jni::static_ref_cast<CxxModuleWrapper::javaobject>(module);
|
||||||
|
// Then, we grab the CxxModule from the wrapper, which is no longer needed.
|
||||||
|
return cxxModule->cthis()->getModule();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
|
||||||
|
std::weak_ptr<Instance> winstance,
|
||||||
|
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||||
|
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
|
||||||
|
std::vector<std::unique_ptr<NativeModule>> modules;
|
||||||
|
for (const auto& jm : *javaModules) {
|
||||||
|
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
|
||||||
|
}
|
||||||
|
for (const auto& cm : *cxxModules) {
|
||||||
|
modules.emplace_back(
|
||||||
|
folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider()));
|
||||||
|
}
|
||||||
|
if (modules.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return folly::make_unique<ModuleRegistry>(std::move(modules));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <cxxreact/CxxModule.h>
|
||||||
|
#include <cxxreact/ModuleRegistry.h>
|
||||||
|
#include <fb/fbjni.h>
|
||||||
|
|
||||||
|
#include "CxxModuleWrapper.h"
|
||||||
|
#include "JavaModuleWrapper.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
class ModuleHolder : public jni::JavaClass<ModuleHolder> {
|
||||||
|
public:
|
||||||
|
static auto constexpr kJavaDescriptor =
|
||||||
|
"Lcom/facebook/react/cxxbridge/ModuleHolder;";
|
||||||
|
|
||||||
|
std::string getName() const;
|
||||||
|
xplat::module::CxxModule::Provider getProvider() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
|
||||||
|
std::weak_ptr<Instance> winstance,
|
||||||
|
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||||
|
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := libreactnativefb
|
LOCAL_MODULE := libreactnativefb
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
CxxMessageQueue.cpp \
|
||||||
CxxNativeModule.cpp \
|
CxxNativeModule.cpp \
|
||||||
Instance.cpp \
|
Instance.cpp \
|
||||||
JSCExecutor.cpp \
|
JSCExecutor.cpp \
|
||||||
|
|
|
@ -50,6 +50,8 @@ class CxxModule {
|
||||||
class SyncTagType {};
|
class SyncTagType {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef std::function<std::unique_ptr<CxxModule>()> Provider;
|
||||||
|
|
||||||
typedef std::function<void(std::vector<folly::dynamic>)> Callback;
|
typedef std::function<void(std::vector<folly::dynamic>)> Callback;
|
||||||
|
|
||||||
constexpr static AsyncTagType AsyncTag = AsyncTagType();
|
constexpr static AsyncTagType AsyncTag = AsyncTagType();
|
||||||
|
|
|
@ -47,18 +47,19 @@ CxxModule::Callback convertCallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
CxxNativeModule::CxxNativeModule(std::weak_ptr<Instance> instance,
|
CxxNativeModule::CxxNativeModule(std::weak_ptr<Instance> instance,
|
||||||
std::unique_ptr<CxxModule> module)
|
std::string name,
|
||||||
|
CxxModule::Provider provider)
|
||||||
: instance_(instance)
|
: instance_(instance)
|
||||||
, module_(std::move(module))
|
, name_(std::move(name))
|
||||||
, methods_(module_->getMethods()) {
|
, provider_(provider) {}
|
||||||
module_->setInstance(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CxxNativeModule::getName() {
|
std::string CxxNativeModule::getName() {
|
||||||
return module_->getName();
|
return name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
|
std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
|
||||||
|
lazyInit();
|
||||||
|
|
||||||
std::vector<MethodDescriptor> descs;
|
std::vector<MethodDescriptor> descs;
|
||||||
for (auto& method : methods_) {
|
for (auto& method : methods_) {
|
||||||
assert(method.func || method.syncFunc);
|
assert(method.func || method.syncFunc);
|
||||||
|
@ -68,6 +69,8 @@ std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
folly::dynamic CxxNativeModule::getConstants() {
|
folly::dynamic CxxNativeModule::getConstants() {
|
||||||
|
lazyInit();
|
||||||
|
|
||||||
folly::dynamic constants = folly::dynamic::object();
|
folly::dynamic constants = folly::dynamic::object();
|
||||||
for (auto& pair : module_->getConstants()) {
|
for (auto& pair : module_->getConstants()) {
|
||||||
constants.insert(std::move(pair.first), std::move(pair.second));
|
constants.insert(std::move(pair.first), std::move(pair.second));
|
||||||
|
@ -168,5 +171,15 @@ MethodCallResult CxxNativeModule::callSerializableNativeHook(
|
||||||
return method.syncFunc(std::move(args));
|
return method.syncFunc(std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CxxNativeModule::lazyInit() {
|
||||||
|
if (module_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_ = provider_();
|
||||||
|
methods_ = module_->getMethods();
|
||||||
|
module_->setInstance(instance_);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ std::function<void(folly::dynamic)> makeCallback(
|
||||||
|
|
||||||
class CxxNativeModule : public NativeModule {
|
class CxxNativeModule : public NativeModule {
|
||||||
public:
|
public:
|
||||||
CxxNativeModule(std::weak_ptr<Instance> instance,
|
CxxNativeModule(std::weak_ptr<Instance> instance, std::string name,
|
||||||
std::unique_ptr<xplat::module::CxxModule> module);
|
xplat::module::CxxModule::Provider provider);
|
||||||
|
|
||||||
std::string getName() override;
|
std::string getName() override;
|
||||||
std::vector<MethodDescriptor> getMethods() override;
|
std::vector<MethodDescriptor> getMethods() override;
|
||||||
|
@ -27,7 +27,11 @@ public:
|
||||||
ExecutorToken token, unsigned int hookId, folly::dynamic&& args) override;
|
ExecutorToken token, unsigned int hookId, folly::dynamic&& args) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void lazyInit();
|
||||||
|
|
||||||
std::weak_ptr<Instance> instance_;
|
std::weak_ptr<Instance> instance_;
|
||||||
|
std::string name_;
|
||||||
|
xplat::module::CxxModule::Provider provider_;
|
||||||
std::unique_ptr<xplat::module::CxxModule> module_;
|
std::unique_ptr<xplat::module::CxxModule> module_;
|
||||||
std::vector<xplat::module::CxxModule::Method> methods_;
|
std::vector<xplat::module::CxxModule::Method> methods_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,7 +40,7 @@ void Instance::initializeBridge(
|
||||||
if (!nativeQueue) {
|
if (!nativeQueue) {
|
||||||
// TODO pass down a thread/queue from java, instead of creating our own.
|
// TODO pass down a thread/queue from java, instead of creating our own.
|
||||||
|
|
||||||
auto queue = std::make_unique<CxxMessageQueue>();
|
auto queue = folly::make_unique<CxxMessageQueue>();
|
||||||
std::thread t(queue->getUnregisteredRunLoop());
|
std::thread t(queue->getUnregisteredRunLoop());
|
||||||
t.detach();
|
t.detach();
|
||||||
nativeQueue = std::move(queue);
|
nativeQueue = std::move(queue);
|
||||||
|
|
|
@ -361,12 +361,8 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
||||||
|
|
||||||
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
|
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
|
||||||
|
|
||||||
// TODO(luk): t13903306 Remove this check once we make native modules
|
|
||||||
// working for java2js
|
|
||||||
if (m_delegate) {
|
|
||||||
bindBridge();
|
bindBridge();
|
||||||
flush();
|
flush();
|
||||||
}
|
|
||||||
|
|
||||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
||||||
|
@ -416,11 +412,8 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
||||||
evaluateScript(m_context, jsScript, jsSourceURL);
|
evaluateScript(m_context, jsScript, jsSourceURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(luk): t13903306 Remove this check once we make native modules working for java2js
|
|
||||||
if (m_delegate) {
|
|
||||||
bindBridge();
|
bindBridge();
|
||||||
flush();
|
flush();
|
||||||
}
|
|
||||||
|
|
||||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
||||||
|
@ -435,6 +428,9 @@ 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()) {
|
||||||
|
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()) {
|
if (batchedBridgeValue.isUndefined()) {
|
||||||
|
@ -466,8 +462,19 @@ void JSCExecutor::callNativeModules(Value&& value) {
|
||||||
|
|
||||||
void JSCExecutor::flush() {
|
void JSCExecutor::flush() {
|
||||||
SystraceSection s("JSCExecutor::flush");
|
SystraceSection s("JSCExecutor::flush");
|
||||||
|
if (!m_delegate) {
|
||||||
|
// do nothing
|
||||||
|
} 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({}));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
|
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
|
||||||
SystraceSection s("JSCExecutor::callFunction");
|
SystraceSection s("JSCExecutor::callFunction");
|
||||||
|
@ -476,6 +483,9 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
|
||||||
|
|
||||||
auto result = [&] {
|
auto result = [&] {
|
||||||
try {
|
try {
|
||||||
|
// See flush()
|
||||||
|
CHECK(m_callFunctionReturnFlushedQueueJS)
|
||||||
|
<< "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)),
|
||||||
|
@ -511,6 +521,8 @@ 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()
|
||||||
|
CHECK(m_callFunctionReturnResultAndFlushedQueueJS);
|
||||||
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)),
|
||||||
|
|
|
@ -11,6 +11,10 @@ JSCNativeModules::JSCNativeModules(std::shared_ptr<ModuleRegistry> moduleRegistr
|
||||||
m_moduleRegistry(std::move(moduleRegistry)) {}
|
m_moduleRegistry(std::move(moduleRegistry)) {}
|
||||||
|
|
||||||
JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
|
JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
|
||||||
|
if (!m_moduleRegistry) {
|
||||||
|
return Value::makeUndefined(context);
|
||||||
|
}
|
||||||
|
|
||||||
std::string moduleName = String::ref(context, jsName).str();
|
std::string moduleName = String::ref(context, jsName).str();
|
||||||
|
|
||||||
const auto it = m_objects.find(moduleName);
|
const auto it = m_objects.find(moduleName);
|
||||||
|
|
|
@ -47,6 +47,9 @@ public:
|
||||||
|
|
||||||
void callNativeModules(
|
void callNativeModules(
|
||||||
JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
|
JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
|
||||||
|
|
||||||
|
CHECK(m_registry || calls.empty()) <<
|
||||||
|
"native module calls cannot be completed with no native modules";
|
||||||
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
|
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
|
||||||
m_nativeQueue->runOnQueue([this, token, calls=std::move(calls), isEndOfBatch] () mutable {
|
m_nativeQueue->runOnQueue([this, token, calls=std::move(calls), isEndOfBatch] () mutable {
|
||||||
// An exception anywhere in here stops processing of the batch. This
|
// An exception anywhere in here stops processing of the batch. This
|
||||||
|
@ -95,13 +98,8 @@ NativeToJsBridge::NativeToJsBridge(
|
||||||
std::shared_ptr<InstanceCallback> callback)
|
std::shared_ptr<InstanceCallback> callback)
|
||||||
: m_destroyed(std::make_shared<bool>(false))
|
: m_destroyed(std::make_shared<bool>(false))
|
||||||
, m_mainExecutorToken(callback->createExecutorToken())
|
, m_mainExecutorToken(callback->createExecutorToken())
|
||||||
, m_delegate(registry
|
, m_delegate(std::make_shared<JsToNativeBridge>(
|
||||||
? std::make_shared<JsToNativeBridge>(
|
this, registry, std::move(nativeQueue), callback)) {
|
||||||
this, registry, std::move(nativeQueue), callback)
|
|
||||||
: nullptr) {
|
|
||||||
if (!m_delegate) {
|
|
||||||
nativeQueue->quitSynchronous();
|
|
||||||
}
|
|
||||||
std::unique_ptr<JSExecutor> mainExecutor =
|
std::unique_ptr<JSExecutor> mainExecutor =
|
||||||
jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
|
jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
|
||||||
// cached to avoid locked map lookup in the common case
|
// cached to avoid locked map lookup in the common case
|
||||||
|
@ -318,9 +316,7 @@ ExecutorToken NativeToJsBridge::getTokenForExecutor(JSExecutor& executor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeToJsBridge::destroy() {
|
void NativeToJsBridge::destroy() {
|
||||||
if (m_delegate) {
|
|
||||||
m_delegate->quitQueueSynchronous();
|
m_delegate->quitQueueSynchronous();
|
||||||
}
|
|
||||||
auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken);
|
auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken);
|
||||||
// All calls made through runOnExecutorQueue have an early exit if
|
// All calls made through runOnExecutorQueue have an early exit if
|
||||||
// m_destroyed is true. Setting this before the runOnQueueSync will cause
|
// m_destroyed is true. Setting this before the runOnQueueSync will cause
|
||||||
|
|
|
@ -305,6 +305,10 @@ public:
|
||||||
return Value(ctx, JSC_JSValueMakeUndefined(ctx));
|
return Value(ctx, JSC_JSValueMakeUndefined(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Value makeNull(JSContextRef ctx) {
|
||||||
|
return Value(ctx, JSC_JSValueMakeNull(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
std::string toJSONString(unsigned indent = 0) const;
|
std::string toJSONString(unsigned indent = 0) const;
|
||||||
static Value fromJSON(JSContextRef ctx, const String& json);
|
static Value fromJSON(JSContextRef ctx, const String& json);
|
||||||
static JSValueRef fromDynamic(JSContextRef ctx, const folly::dynamic& value);
|
static JSValueRef fromDynamic(JSContextRef ctx, const folly::dynamic& value);
|
||||||
|
|
Loading…
Reference in New Issue