Reviewed By: astreet

Differential Revision: D3276230

fbshipit-source-id: b3ab7e7dc149696b7db1049613fbb6a2a19bc8fb
This commit is contained in:
Alexander Blom 2016-05-11 11:38:47 -07:00 коммит произвёл Facebook Github Bot 2
Родитель 4a7f2192f9
Коммит 0934470676
8 изменённых файлов: 47 добавлений и 216 удалений

Просмотреть файл

@ -23,7 +23,7 @@ import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.CatalystInstanceImpl;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSCJavaScriptExecutor;
import com.facebook.react.bridge.JavaScriptModulesConfig;
import com.facebook.react.bridge.JavaScriptModuleRegistry;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
import com.facebook.react.bridge.NativeModuleRegistry;
@ -38,8 +38,8 @@ public class ReactTestHelper {
private @Nullable Context mContext;
private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder =
new NativeModuleRegistry.Builder();
private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder =
new JavaScriptModulesConfig.Builder();
private final JavaScriptModuleRegistry.Builder mJSModuleRegistryBuilder =
new JavaScriptModuleRegistry.Builder();
@Override
public ReactInstanceEasyBuilder setContext(Context context) {
@ -55,7 +55,7 @@ public class ReactTestHelper {
@Override
public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
mJSModulesConfigBuilder.add(moduleInterfaceClass);
mJSModuleRegistryBuilder.add(moduleInterfaceClass);
return this;
}
@ -65,7 +65,7 @@ public class ReactTestHelper {
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(new JSCJavaScriptExecutor(new WritableNativeMap()))
.setRegistry(mNativeModuleRegistryBuilder.build())
.setJSModulesConfig(mJSModulesConfigBuilder.build())
.setJSModuleRegistry(mJSModuleRegistryBuilder.build())
.setJSBundleLoader(JSBundleLoader.createFileLoader(
mContext,
"assets://AndroidTestBundle.js"))

Просмотреть файл

@ -37,7 +37,7 @@ import com.facebook.react.bridge.JSCJavaScriptExecutor;
import com.facebook.react.bridge.JavaJSExecutor;
import com.facebook.react.bridge.JavaScriptExecutor;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.JavaScriptModulesConfig;
import com.facebook.react.bridge.JavaScriptModuleRegistry;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
import com.facebook.react.bridge.NativeModuleRegistry;
@ -759,7 +759,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
// CREATE_REACT_CONTEXT_END is in JSCExecutor.cpp
mSourceUrl = jsBundleLoader.getSourceUrl();
NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
if (mUseDeveloperSupport) {
@ -801,15 +801,6 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
}
ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_START);
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildJSModuleConfig");
JavaScriptModulesConfig javaScriptModulesConfig;
try {
javaScriptModulesConfig = jsModulesBuilder.build();
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_END);
}
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
@ -818,7 +809,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
.setJSModulesConfig(javaScriptModulesConfig)
.setJSModuleRegistry(jsModulesBuilder.build())
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
@ -876,7 +867,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
ReactPackage reactPackage,
ReactApplicationContext reactContext,
NativeModuleRegistry.Builder nativeRegistryBuilder,
JavaScriptModulesConfig.Builder jsModulesBuilder) {
JavaScriptModuleRegistry.Builder jsModulesBuilder) {
for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) {
nativeRegistryBuilder.add(nativeModule);
}

Просмотреть файл

@ -72,7 +72,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry registry,
final JavaScriptModulesConfig jsModulesConfig,
final JavaScriptModuleRegistry jsModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
FLog.d(ReactConstants.TAG, "Initializing React Bridge.");
@ -81,7 +81,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mJavaRegistry = registry;
mJSModuleRegistry = new JavaScriptModuleRegistry(CatalystInstanceImpl.this, jsModulesConfig);
mJSModuleRegistry = jsModuleRegistry;
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mTraceListener = new JSProfilerTraceListener();
@ -93,7 +93,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
public ReactBridge call() throws Exception {
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
try {
return initializeBridge(jsExecutor, jsModulesConfig);
return initializeBridge(jsExecutor);
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
@ -104,9 +104,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
}
}
private ReactBridge initializeBridge(
JavaScriptExecutor jsExecutor,
JavaScriptModulesConfig jsModulesConfig) {
private ReactBridge initializeBridge(JavaScriptExecutor jsExecutor) {
mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
@ -126,7 +124,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
try {
bridge.setGlobalVariable(
"__fbBatchedBridgeConfig",
buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
buildModulesConfigJSONProperty(mJavaRegistry));
bridge.setGlobalVariable(
"__RCTProfileIsProfiling",
Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false");
@ -280,7 +278,8 @@ public class CatalystInstanceImpl implements CatalystInstance {
@Override
public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(executorToken, jsInterface);
return Assertions.assertNotNull(mJSModuleRegistry)
.getJavaScriptModule(this, executorToken, jsInterface);
}
@Override
@ -350,17 +349,13 @@ public class CatalystInstanceImpl implements CatalystInstance {
mBridge.setGlobalVariable(propName, jsonValue);
}
private String buildModulesConfigJSONProperty(
NativeModuleRegistry nativeModuleRegistry,
JavaScriptModulesConfig jsModulesConfig) {
private String buildModulesConfigJSONProperty(NativeModuleRegistry nativeModuleRegistry) {
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
try {
writer.beginObject();
writer.name("remoteModuleConfig");
nativeModuleRegistry.writeModuleDescriptions(writer);
writer.name("localModulesConfig");
jsModulesConfig.writeModuleDescriptions(writer);
writer.endObject();
return stringWriter.toString();
} catch (IOException ioe) {
@ -504,7 +499,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
private @Nullable JSBundleLoader mJSBundleLoader;
private @Nullable NativeModuleRegistry mRegistry;
private @Nullable JavaScriptModulesConfig mJSModulesConfig;
private @Nullable JavaScriptModuleRegistry mJSModuleRegistry;
private @Nullable JavaScriptExecutor mJSExecutor;
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
@ -519,8 +514,8 @@ public class CatalystInstanceImpl implements CatalystInstance {
return this;
}
public Builder setJSModulesConfig(JavaScriptModulesConfig jsModulesConfig) {
mJSModulesConfig = jsModulesConfig;
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
mJSModuleRegistry = jsModuleRegistry;
return this;
}
@ -545,7 +540,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
Assertions.assertNotNull(mReactQueueConfigurationSpec),
Assertions.assertNotNull(mJSExecutor),
Assertions.assertNotNull(mRegistry),
Assertions.assertNotNull(mJSModulesConfig),
Assertions.assertNotNull(mJSModuleRegistry),
Assertions.assertNotNull(mJSBundleLoader),
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
}

Просмотреть файл

@ -15,7 +15,9 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.WeakHashMap;
import com.facebook.common.logging.FLog;
@ -29,23 +31,21 @@ import com.facebook.react.common.ReactConstants;
* JavaScript.
*/
public class JavaScriptModuleRegistry {
private final CatalystInstance mCatalystInstance;
private final WeakHashMap<ExecutorToken, HashMap<Class<? extends JavaScriptModule>, JavaScriptModule>> mModuleInstances;
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations;
public JavaScriptModuleRegistry(
CatalystInstance instance,
JavaScriptModulesConfig config) {
mCatalystInstance = instance;
public JavaScriptModuleRegistry(List<JavaScriptModuleRegistration> config) {
mModuleInstances = new WeakHashMap<>();
mModuleRegistrations = new HashMap<>();
for (JavaScriptModuleRegistration registration : config.getModuleDefinitions()) {
for (JavaScriptModuleRegistration registration : config) {
mModuleRegistrations.put(registration.getModuleInterface(), registration);
}
}
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(ExecutorToken executorToken, Class<T> moduleInterface) {
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
CatalystInstance instance,
ExecutorToken executorToken,
Class<T> moduleInterface) {
HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> instancesForContext =
mModuleInstances.get(executorToken);
if (instancesForContext == null) {
@ -65,11 +65,25 @@ public class JavaScriptModuleRegistry {
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
moduleInterface.getClassLoader(),
new Class[]{moduleInterface},
new JavaScriptModuleInvocationHandler(executorToken, mCatalystInstance, registration));
new JavaScriptModuleInvocationHandler(executorToken, instance, registration));
instancesForContext.put(moduleInterface, interfaceProxy);
return (T) interfaceProxy;
}
public static class Builder {
private List<JavaScriptModuleRegistration> mModules =
new ArrayList<JavaScriptModuleRegistration>();
public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
mModules.add(new JavaScriptModuleRegistration(moduleInterfaceClass));
return this;
}
public JavaScriptModuleRegistry build() {
return new JavaScriptModuleRegistry(mModules);
}
}
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
private final WeakReference<ExecutorToken> mExecutorToken;

Просмотреть файл

@ -1,71 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Class stores configuration of javascript modules that can be used across the bridge
*/
public class JavaScriptModulesConfig {
private final List<JavaScriptModuleRegistration> mModules;
public JavaScriptModulesConfig(List<JavaScriptModuleRegistration> modules) {
mModules = modules;
}
public List<JavaScriptModuleRegistration> getModuleDefinitions() {
return mModules;
}
public void writeModuleDescriptions(JsonWriter writer) throws IOException {
writer.beginObject();
for (JavaScriptModuleRegistration registration : mModules) {
writer.name(registration.getName()).beginObject();
appendJSModuleToJSONObject(writer, registration);
writer.endObject();
}
writer.endObject();
}
private void appendJSModuleToJSONObject(
JsonWriter writer,
JavaScriptModuleRegistration registration) throws IOException {
writer.name("moduleID").value(registration.getName());
writer.name("methods").beginObject();
for (Method method : registration.getMethods()) {
writer.name(method.getName()).beginObject();
writer.name("methodID").value(method.getName());
writer.endObject();
}
writer.endObject();
if (registration.getModuleInterface().isAnnotationPresent(SupportsWebWorkers.class)) {
writer.name("supportsWebWorkers").value(true);
}
}
public static class Builder {
private List<JavaScriptModuleRegistration> mModules =
new ArrayList<JavaScriptModuleRegistration>();
public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
mModules.add(new JavaScriptModuleRegistration(moduleInterfaceClass));
return this;
}
public JavaScriptModulesConfig build() {
return new JavaScriptModulesConfig(mModules);
}
}
}

Просмотреть файл

@ -1,95 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
import java.io.IOException;
import java.io.StringWriter;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import static org.fest.assertions.api.Assertions.assertThat;
public class JavaScriptModuleConfigTest {
private static interface SomeModule extends JavaScriptModule {
public void stringMethod(String arg);
public void intMethod(int arg);
}
private static interface OtherModule extends JavaScriptModule {
public void method(String arg1, int arg2);
}
@Test
public void testModuleWithMethods() throws Exception {
JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
.add(SomeModule.class)
.build();
String json = getModuleDescriptions(jsModulesConfig);
JsonNode node = parse(json);
assertThat(node).hasSize(1);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode methods = module.get("methods");
assertThat(methods)
.isNotNull()
.hasSize(2);
JsonNode intMethodNode = methods.get("intMethod");
assertThat(intMethodNode).isNotNull();
assertThat(intMethodNode.get("methodID").asText()).isEqualTo("intMethod");
JsonNode stringMethod = methods.get("stringMethod");
assertThat(stringMethod).isNotNull();
assertThat(stringMethod.get("methodID").asText()).isEqualTo("stringMethod");
}
@Test
public void testMultipleModules() throws Exception {
JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
.add(OtherModule.class)
.add(SomeModule.class)
.build();
String json = getModuleDescriptions(jsModulesConfig);
JsonNode node = parse(json);
assertThat(node).hasSize(2);
JsonNode someModuleNode = node.get("SomeModule");
assertThat(someModuleNode).isNotNull();
String someModuleID = someModuleNode.get("moduleID").asText();
JsonNode otherModuleNode = node.get("OtherModule");
assertThat(otherModuleNode).isNotNull();
String otherModuleID = otherModuleNode.get("moduleID").asText();
assertThat(otherModuleID)
.isNotEqualTo(someModuleID);
}
private static String getModuleDescriptions(JavaScriptModulesConfig jsModulesConfig)
throws IOException {
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
jsModulesConfig.writeModuleDescriptions(writer);
writer.close();
return stringWriter.getBuffer().toString();
}
private JsonNode parse(String json) throws Exception {
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(json);
}
}

Просмотреть файл

@ -67,8 +67,7 @@ void Instance::initializeBridge(
std::shared_ptr<JSExecutorFactory> jsef,
std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry,
folly::dynamic jsModuleDescriptions) {
std::shared_ptr<ModuleRegistry> moduleRegistry) {
callback_ = std::move(callback);
nativeQueue_ = std::move(nativeQueue);
jsQueue_ = jsQueue;
@ -94,8 +93,7 @@ void Instance::initializeBridge(
folly::dynamic config =
folly::dynamic::object
("remoteModuleConfig", std::move(nativeModuleDescriptions))
("localModulesConfig", std::move(jsModuleDescriptions));
("remoteModuleConfig", std::move(nativeModuleDescriptions));
#ifdef WITH_FBSYSTRACE
FbSystraceSection t(TRACE_TAG_REACT_CXX_BRIDGE, "setGlobalVariable");

Просмотреть файл

@ -32,8 +32,7 @@ class Instance {
std::shared_ptr<JSExecutorFactory> jsef,
std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry,
folly::dynamic jsModuleDescriptions);
std::shared_ptr<ModuleRegistry> moduleRegistry);
void loadScriptFromString(const std::string& string, const std::string& sourceURL);
void loadScriptFromFile(const std::string& filename, const std::string& sourceURL);
void loadUnbundle(