mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Kotlinify JavaScriptModuleRegistry (#51164)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51164 As per title. Changelog: [Internal] Reviewed By: javache Differential Revision: D74326679 fbshipit-source-id: ecd15fda9ea8686b65171c462e7e82dc9609377b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
84253c4e20
commit
1908b3dfac
@@ -921,9 +921,14 @@ public abstract interface class com/facebook/react/bridge/JavaScriptModule {
|
||||
}
|
||||
|
||||
public final class com/facebook/react/bridge/JavaScriptModuleRegistry {
|
||||
public static final field Companion Lcom/facebook/react/bridge/JavaScriptModuleRegistry$Companion;
|
||||
public fun <init> ()V
|
||||
public static fun getJSModuleName (Ljava/lang/Class;)Ljava/lang/String;
|
||||
public fun getJavaScriptModule (Lcom/facebook/react/bridge/CatalystInstance;Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
|
||||
public static final fun getJSModuleName (Ljava/lang/Class;)Ljava/lang/String;
|
||||
public final fun getJavaScriptModule (Lcom/facebook/react/bridge/CatalystInstance;Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/bridge/JavaScriptModuleRegistry$Companion {
|
||||
public final fun getJSModuleName (Ljava/lang/Class;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/bridge/JsonWriterHelper {
|
||||
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class responsible for holding all the {@link JavaScriptModule}s. Uses Java proxy objects to
|
||||
* dispatch method calls on JavaScriptModules to the bridge using the corresponding module and
|
||||
* method ids so the proper function is executed in JavaScript.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public final class JavaScriptModuleRegistry {
|
||||
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
|
||||
|
||||
public JavaScriptModuleRegistry() {
|
||||
mModuleInstances = new HashMap<>();
|
||||
}
|
||||
|
||||
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
|
||||
CatalystInstance instance, Class<T> moduleInterface) {
|
||||
JavaScriptModule module = mModuleInstances.get(moduleInterface);
|
||||
if (module != null) {
|
||||
return (T) module;
|
||||
}
|
||||
|
||||
JavaScriptModule interfaceProxy =
|
||||
(JavaScriptModule)
|
||||
Proxy.newProxyInstance(
|
||||
moduleInterface.getClassLoader(),
|
||||
new Class[] {moduleInterface},
|
||||
new JavaScriptModuleInvocationHandler(instance, moduleInterface));
|
||||
mModuleInstances.put(moduleInterface, interfaceProxy);
|
||||
return (T) interfaceProxy;
|
||||
}
|
||||
|
||||
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
|
||||
private final CatalystInstance mCatalystInstance;
|
||||
private final Class<? extends JavaScriptModule> mModuleInterface;
|
||||
private @Nullable String mName;
|
||||
|
||||
public JavaScriptModuleInvocationHandler(
|
||||
CatalystInstance catalystInstance, Class<? extends JavaScriptModule> moduleInterface) {
|
||||
mCatalystInstance = catalystInstance;
|
||||
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) {
|
||||
// Getting the class name every call is expensive, so cache it
|
||||
mName = JavaScriptModuleRegistry.getJSModuleName(mModuleInterface);
|
||||
}
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
|
||||
throws Throwable {
|
||||
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
|
||||
mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJSModuleName(Class<? extends JavaScriptModule> jsModuleInterface) {
|
||||
// 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 = jsModuleInterface.getSimpleName();
|
||||
int dollarSignIndex = name.lastIndexOf('$');
|
||||
if (dollarSignIndex != -1) {
|
||||
name = name.substring(dollarSignIndex + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import com.facebook.react.common.build.ReactBuildConfig
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* Class responsible for holding all the [JavaScriptModule]s. Uses Java proxy objects to dispatch
|
||||
* method calls on JavaScriptModules to the bridge using the corresponding module and method ids so
|
||||
* the proper function is executed in JavaScript.
|
||||
*/
|
||||
public class JavaScriptModuleRegistry {
|
||||
|
||||
private val moduleInstances: MutableMap<Class<out JavaScriptModule>, JavaScriptModule> = HashMap()
|
||||
|
||||
@Synchronized
|
||||
public fun <T : JavaScriptModule> getJavaScriptModule(
|
||||
@Suppress("DEPRECATION") instance: CatalystInstance,
|
||||
moduleInterface: Class<T>
|
||||
): T {
|
||||
val module = moduleInstances[moduleInterface]
|
||||
if (module != null) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return module as T
|
||||
}
|
||||
|
||||
val proxy =
|
||||
Proxy.newProxyInstance(
|
||||
moduleInterface.classLoader,
|
||||
arrayOf<Class<*>>(moduleInterface),
|
||||
JavaScriptModuleInvocationHandler(instance, moduleInterface)) as JavaScriptModule
|
||||
|
||||
moduleInstances[moduleInterface] = proxy
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return proxy as T
|
||||
}
|
||||
|
||||
private class JavaScriptModuleInvocationHandler(
|
||||
@Suppress("DEPRECATION") private val catalystInstance: CatalystInstance,
|
||||
private val moduleInterface: Class<out JavaScriptModule>
|
||||
) : InvocationHandler {
|
||||
|
||||
private var name: String? = null
|
||||
|
||||
init {
|
||||
if (ReactBuildConfig.DEBUG) {
|
||||
val methodNames = mutableSetOf<String>()
|
||||
for (method in moduleInterface.declaredMethods) {
|
||||
if (!methodNames.add(method.name)) {
|
||||
throw AssertionError(
|
||||
"Method overloading is unsupported: ${moduleInterface.name}#${method.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getJSModuleName(): String {
|
||||
// Getting the class name every call is expensive, so cache it
|
||||
return name ?: getJSModuleName(moduleInterface).also { name = it }
|
||||
}
|
||||
|
||||
public override fun invoke(proxy: Any, method: Method, args: Array<Any?>?): Any? {
|
||||
val jsArgs = if (args != null) Arguments.fromJavaArgs(args) else WritableNativeArray()
|
||||
catalystInstance.callFunction(getJSModuleName(), method.name, jsArgs)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun getJSModuleName(jsModuleInterface: Class<out JavaScriptModule>): String {
|
||||
var name = jsModuleInterface.simpleName
|
||||
val dollarSignIndex = name.lastIndexOf('$')
|
||||
if (dollarSignIndex != -1) {
|
||||
name = name.substring(dollarSignIndex + 1)
|
||||
}
|
||||
return name
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user