diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index 6d05c003a..82d347c8c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -341,4 +341,9 @@ public abstract class BaseJavaModule implements NativeModule { public void onCatalystInstanceDestroy() { // do nothing } + + @Override + public boolean supportsWebWorkers() { + return false; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java index abeba7230..e6241f6e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java @@ -52,6 +52,9 @@ public class JavaScriptModulesConfig { jg.writeEndObject(); } jg.writeEndObject(); + if (registration.getModuleInterface().isAnnotationPresent(SupportsWebWorkers.class)) { + jg.writeBooleanField("supportsWebWorkers", true); + } } public static class Builder { diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java index 5dae9ac3e..8996547f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java @@ -72,4 +72,9 @@ public interface NativeModule { * Called before {CatalystInstance#onHostDestroy} */ void onCatalystInstanceDestroy(); + + /** + * Whether this native module supports calls from web workers. Ignored for now. + */ + boolean supportsWebWorkers(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java index 131def5fb..c8a59e8f7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java @@ -65,6 +65,7 @@ public class NativeModuleRegistry { for (ModuleDefinition moduleDef : mModuleTable) { jg.writeObjectFieldStart(moduleDef.name); jg.writeNumberField("moduleID", moduleDef.id); + jg.writeBooleanField("supportsWebWorkers", moduleDef.target.supportsWebWorkers()); jg.writeObjectFieldStart("methods"); for (int i = 0; i < moduleDef.methods.size(); i++) { MethodRegistration method = moduleDef.methods.get(i); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java new file mode 100644 index 000000000..ad3dc87f4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java @@ -0,0 +1,15 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.bridge; + +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation indicating that a JS module should be made available to web + * workers spawned by the main JS executor. + */ +@Retention(RUNTIME) +public @interface SupportsWebWorkers { +} diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp index 5720905e7..38dd9e237 100644 --- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp +++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp @@ -97,7 +97,8 @@ JSCExecutor::JSCExecutor( Bridge *bridge, int workerId, JSCExecutor *owner, - const std::string& script) : + const std::string& script, + const std::unordered_map& globalObjAsJSON) : m_bridge(bridge), m_workerId(workerId), m_owner(owner), @@ -105,11 +106,15 @@ JSCExecutor::JSCExecutor( m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) { // We post initOnJSVMThread here so that the owner doesn't have to wait for // initialization on its own thread - m_messageQueueThread->runOnQueue([this, script] () { + m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () { initOnJSVMThread(); installGlobalFunction(m_context, "postMessage", nativePostMessage); + for (auto& it : globalObjAsJSON) { + setGlobalVariable(it.first, it.second); + } + // TODO(9604438): Protect against script does not exist std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script); // TODO(9994180): Throw on error @@ -302,14 +307,17 @@ void JSCExecutor::loadModule(uint32_t moduleId) { int JSCExecutor::addWebWorker( const std::string& script, - JSValueRef workerRef) { + JSValueRef workerRef, + JSValueRef globalObjRef) { static std::atomic_int nextWorkerId(1); int workerId = nextWorkerId++; + Object globalObj = Value(m_context, globalObjRef).asObject(); + auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get()); std::unique_ptr worker; - workerMQT->runOnQueueSync([this, &worker, &script, workerId] () { - worker.reset(new JSCExecutor(m_bridge, workerId, this, script)); + workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () { + worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap())); }); Object workerObj = Value(m_context, workerRef).asObject(); @@ -487,7 +495,7 @@ JSValueRef JSCExecutor::nativeStartWorker( size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { - if (argumentCount != 2) { + if (argumentCount != 3) { *exception = createErrorString(ctx, "Got wrong number of args"); return JSValueMakeUndefined(ctx); } @@ -495,6 +503,7 @@ JSValueRef JSCExecutor::nativeStartWorker( std::string scriptFile = Value(ctx, arguments[0]).toString().str(); JSValueRef worker = arguments[1]; + JSValueRef globalObj = arguments[2]; JSCExecutor *executor; try { @@ -504,7 +513,7 @@ JSValueRef JSCExecutor::nativeStartWorker( return JSValueMakeUndefined(ctx); } - int workerId = executor->addWebWorker(scriptFile, worker); + int workerId = executor->addWebWorker(scriptFile, worker, globalObj); return JSValueMakeNumber(ctx, workerId); } diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h index c60f33422..6b2669dbe 100644 --- a/ReactAndroid/src/main/jni/react/JSCExecutor.h +++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h @@ -92,7 +92,8 @@ private: Bridge *bridge, int workerId, JSCExecutor *owner, - const std::string& script); + const std::string& script, + const std::unordered_map& globalObjAsJSON); void initOnJSVMThread(); void terminateOnJSVMThread(); @@ -100,7 +101,7 @@ private: void flushQueueImmediate(std::string queueJSON); void loadModule(uint32_t moduleId); - int addWebWorker(const std::string& script, JSValueRef workerRef); + int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef); void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn); void postMessageToOwner(JSValueRef result); void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);