Stop requiring registration of callable JS modules
Reviewed By: AaaChiuuu Differential Revision: D5229073 fbshipit-source-id: d6d1967982ae379733a7e9667515ca9f074aadd4
This commit is contained in:
parent
1d30f833a6
commit
53d5504f40
|
@ -75,7 +75,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
|
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
|
||||||
private final Object mJSCallsPendingInitLock = new Object();
|
private final Object mJSCallsPendingInitLock = new Object();
|
||||||
|
|
||||||
private final NativeModuleRegistry mJavaRegistry;
|
private final NativeModuleRegistry mNativeModuleRegistry;
|
||||||
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||||
private final MessageQueueThread mNativeModulesQueueThread;
|
private final MessageQueueThread mNativeModulesQueueThread;
|
||||||
private final @Nullable MessageQueueThread mUIBackgroundQueueThread;
|
private final @Nullable MessageQueueThread mUIBackgroundQueueThread;
|
||||||
|
@ -92,8 +92,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
private CatalystInstanceImpl(
|
private CatalystInstanceImpl(
|
||||||
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
|
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
|
||||||
final JavaScriptExecutor jsExecutor,
|
final JavaScriptExecutor jsExecutor,
|
||||||
final NativeModuleRegistry registry,
|
final NativeModuleRegistry nativeModuleRegistry,
|
||||||
final JavaScriptModuleRegistry jsModuleRegistry,
|
|
||||||
final JSBundleLoader jsBundleLoader,
|
final JSBundleLoader jsBundleLoader,
|
||||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||||
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
||||||
|
@ -103,8 +102,8 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
reactQueueConfigurationSpec,
|
reactQueueConfigurationSpec,
|
||||||
new NativeExceptionHandler());
|
new NativeExceptionHandler());
|
||||||
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
|
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
|
||||||
mJavaRegistry = registry;
|
mNativeModuleRegistry = nativeModuleRegistry;
|
||||||
mJSModuleRegistry = jsModuleRegistry;
|
mJSModuleRegistry = new JavaScriptModuleRegistry();
|
||||||
mJSBundleLoader = jsBundleLoader;
|
mJSBundleLoader = jsBundleLoader;
|
||||||
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||||
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
|
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
|
||||||
|
@ -118,8 +117,8 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
mReactQueueConfiguration.getJSQueueThread(),
|
mReactQueueConfiguration.getJSQueueThread(),
|
||||||
mNativeModulesQueueThread,
|
mNativeModulesQueueThread,
|
||||||
mUIBackgroundQueueThread,
|
mUIBackgroundQueueThread,
|
||||||
mJavaRegistry.getJavaModules(this),
|
mNativeModuleRegistry.getJavaModules(this),
|
||||||
mJavaRegistry.getCxxModules());
|
mNativeModuleRegistry.getCxxModules());
|
||||||
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
|
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +136,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
public void onBatchComplete() {
|
public void onBatchComplete() {
|
||||||
CatalystInstanceImpl impl = mOuter.get();
|
CatalystInstanceImpl impl = mOuter.get();
|
||||||
if (impl != null) {
|
if (impl != null) {
|
||||||
impl.mJavaRegistry.onBatchComplete();
|
impl.mNativeModuleRegistry.onBatchComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +293,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mJavaRegistry.notifyJSInstanceDestroy();
|
mNativeModuleRegistry.notifyJSInstanceDestroy();
|
||||||
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
|
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
|
||||||
if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||||
|
@ -342,7 +341,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mJavaRegistry.notifyJSInstanceInitialized();
|
mNativeModuleRegistry.notifyJSInstanceInitialized();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -359,19 +358,19 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
|
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
|
||||||
return mJavaRegistry.hasModule(nativeModuleInterface);
|
return mNativeModuleRegistry.hasModule(nativeModuleInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only ever called with UIManagerModule or CurrentViewerModule.
|
// This is only ever called with UIManagerModule or CurrentViewerModule.
|
||||||
@Override
|
@Override
|
||||||
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
|
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
|
||||||
return mJavaRegistry.getModule(nativeModuleInterface);
|
return mNativeModuleRegistry.getModule(nativeModuleInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only used by com.facebook.react.modules.common.ModuleDataCleaner
|
// This is only used by com.facebook.react.modules.common.ModuleDataCleaner
|
||||||
@Override
|
@Override
|
||||||
public Collection<NativeModule> getNativeModules() {
|
public Collection<NativeModule> getNativeModules() {
|
||||||
return mJavaRegistry.getAllModules();
|
return mNativeModuleRegistry.getAllModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void handleMemoryPressureUiHidden();
|
private native void handleMemoryPressureUiHidden();
|
||||||
|
@ -528,7 +527,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
|
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
|
||||||
private @Nullable JSBundleLoader mJSBundleLoader;
|
private @Nullable JSBundleLoader mJSBundleLoader;
|
||||||
private @Nullable NativeModuleRegistry mRegistry;
|
private @Nullable NativeModuleRegistry mRegistry;
|
||||||
private @Nullable JavaScriptModuleRegistry mJSModuleRegistry;
|
|
||||||
private @Nullable JavaScriptExecutor mJSExecutor;
|
private @Nullable JavaScriptExecutor mJSExecutor;
|
||||||
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||||
|
|
||||||
|
@ -544,7 +542,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
|
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
|
||||||
mJSModuleRegistry = jsModuleRegistry;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +566,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||||
Assertions.assertNotNull(mReactQueueConfigurationSpec),
|
Assertions.assertNotNull(mReactQueueConfigurationSpec),
|
||||||
Assertions.assertNotNull(mJSExecutor),
|
Assertions.assertNotNull(mJSExecutor),
|
||||||
Assertions.assertNotNull(mRegistry),
|
Assertions.assertNotNull(mRegistry),
|
||||||
Assertions.assertNotNull(mJSModuleRegistry),
|
|
||||||
Assertions.assertNotNull(mJSBundleLoader),
|
Assertions.assertNotNull(mJSBundleLoader),
|
||||||
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
|
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.facebook.react.common.build.ReactBuildConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registration info for a {@link JavaScriptModule}. Maps its methods to method ids.
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
public class JavaScriptModuleRegistration {
|
|
||||||
|
|
||||||
private final Class<? extends JavaScriptModule> mModuleInterface;
|
|
||||||
private @Nullable String mName;
|
|
||||||
|
|
||||||
public JavaScriptModuleRegistration(Class<? extends JavaScriptModule> moduleInterface) {
|
|
||||||
mModuleInterface = moduleInterface;
|
|
||||||
|
|
||||||
if (ReactBuildConfig.DEBUG) {
|
|
||||||
Set<String> methodNames = new LinkedHashSet<>();
|
|
||||||
for (Method method : mModuleInterface.getDeclaredMethods()) {
|
|
||||||
if (!methodNames.add(method.getName())) {
|
|
||||||
throw new AssertionError(
|
|
||||||
"Method overloading is unsupported: " + mModuleInterface.getName() + "#" +
|
|
||||||
method.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends JavaScriptModule> getModuleInterface() {
|
|
||||||
return mModuleInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
if (mName == null) {
|
|
||||||
// With proguard obfuscation turned on, proguard apparently (poorly) emulates inner classes or
|
|
||||||
// something because Class#getSimpleName() no longer strips the outer class name. We manually
|
|
||||||
// strip it here if necessary.
|
|
||||||
String name = mModuleInterface.getSimpleName();
|
|
||||||
int dollarSignIndex = name.lastIndexOf('$');
|
|
||||||
if (dollarSignIndex != -1) {
|
|
||||||
name = name.substring(dollarSignIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// getting the class name every call is expensive, so cache it
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Method> getMethods() {
|
|
||||||
return Arrays.asList(mModuleInterface.getDeclaredMethods());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,35 +11,25 @@ package com.facebook.react.bridge;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.HashSet;
|
||||||
import java.util.WeakHashMap;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.react.common.build.ReactBuildConfig;
|
||||||
import com.facebook.infer.annotation.Assertions;
|
|
||||||
import com.facebook.react.common.ReactConstants;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class responsible for holding all the {@link JavaScriptModule}s registered to this
|
* Class responsible for holding all the {@link JavaScriptModule}s. Uses Java proxy objects
|
||||||
* {@link CatalystInstance}. Uses Java proxy objects to dispatch method calls on JavaScriptModules
|
* to dispatch method calls on JavaScriptModules to the bridge using the corresponding
|
||||||
* to the bridge using the corresponding module and method ids so the proper function is executed in
|
* module and method ids so the proper function is executed in JavaScript.
|
||||||
* JavaScript.
|
|
||||||
*/
|
*/
|
||||||
public class JavaScriptModuleRegistry {
|
public final class JavaScriptModuleRegistry {
|
||||||
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
|
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
|
||||||
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations;
|
|
||||||
|
|
||||||
public JavaScriptModuleRegistry(List<JavaScriptModuleRegistration> config) {
|
public JavaScriptModuleRegistry() {
|
||||||
mModuleInstances = new HashMap<>();
|
mModuleInstances = new HashMap<>();
|
||||||
mModuleRegistrations = new HashMap<>();
|
|
||||||
for (JavaScriptModuleRegistration registration : config) {
|
|
||||||
mModuleRegistrations.put(registration.getModuleInterface(), registration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
|
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
|
||||||
|
@ -50,51 +40,70 @@ public class JavaScriptModuleRegistry {
|
||||||
return (T) module;
|
return (T) module;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaScriptModuleRegistration registration =
|
|
||||||
Assertions.assertNotNull(
|
|
||||||
mModuleRegistrations.get(moduleInterface),
|
|
||||||
"JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
|
|
||||||
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
|
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
|
||||||
moduleInterface.getClassLoader(),
|
moduleInterface.getClassLoader(),
|
||||||
new Class[]{moduleInterface},
|
new Class[]{moduleInterface},
|
||||||
new JavaScriptModuleInvocationHandler(instance, registration));
|
new JavaScriptModuleInvocationHandler(instance, moduleInterface));
|
||||||
mModuleInstances.put(moduleInterface, interfaceProxy);
|
mModuleInstances.put(moduleInterface, interfaceProxy);
|
||||||
return (T) interfaceProxy;
|
return (T) interfaceProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private List<JavaScriptModuleRegistration> mModules =
|
|
||||||
new ArrayList<JavaScriptModuleRegistration>();
|
|
||||||
|
|
||||||
public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
|
public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
|
||||||
mModules.add(new JavaScriptModuleRegistration(moduleInterfaceClass));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaScriptModuleRegistry build() {
|
public JavaScriptModuleRegistry build() {
|
||||||
return new JavaScriptModuleRegistry(mModules);
|
return new JavaScriptModuleRegistry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
|
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
|
||||||
private final CatalystInstance mCatalystInstance;
|
private final CatalystInstance mCatalystInstance;
|
||||||
private final JavaScriptModuleRegistration mModuleRegistration;
|
private final Class<? extends JavaScriptModule> mModuleInterface;
|
||||||
|
private @Nullable String mName;
|
||||||
|
|
||||||
public JavaScriptModuleInvocationHandler(
|
public JavaScriptModuleInvocationHandler(
|
||||||
CatalystInstance catalystInstance,
|
CatalystInstance catalystInstance,
|
||||||
JavaScriptModuleRegistration moduleRegistration) {
|
Class<? extends JavaScriptModule> moduleInterface) {
|
||||||
mCatalystInstance = catalystInstance;
|
mCatalystInstance = catalystInstance;
|
||||||
mModuleRegistration = moduleRegistration;
|
mModuleInterface = moduleInterface;
|
||||||
|
|
||||||
|
if (ReactBuildConfig.DEBUG) {
|
||||||
|
Set<String> methodNames = new HashSet<>();
|
||||||
|
for (Method method : mModuleInterface.getDeclaredMethods()) {
|
||||||
|
if (!methodNames.add(method.getName())) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"Method overloading is unsupported: " + mModuleInterface.getName() +
|
||||||
|
"#" + method.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getJSModuleName() {
|
||||||
|
if (mName == null) {
|
||||||
|
// With proguard obfuscation turned on, proguard apparently (poorly) emulates inner
|
||||||
|
// classes or something because Class#getSimpleName() no longer strips the outer
|
||||||
|
// class name. We manually strip it here if necessary.
|
||||||
|
String name = mModuleInterface.getSimpleName();
|
||||||
|
int dollarSignIndex = name.lastIndexOf('$');
|
||||||
|
if (dollarSignIndex != -1) {
|
||||||
|
name = name.substring(dollarSignIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// getting the class name every call is expensive, so cache it
|
||||||
|
mName = name;
|
||||||
|
}
|
||||||
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
|
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
|
||||||
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
|
NativeArray jsArgs = args != null
|
||||||
mCatalystInstance.callFunction(
|
? Arguments.fromJavaArgs(args)
|
||||||
mModuleRegistration.getName(),
|
: new WritableNativeArray();
|
||||||
method.getName(),
|
mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
|
||||||
jsArgs
|
|
||||||
);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue