1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
3 #include "JavaReferencesCache.h"
4
5 #include <vector>
6
7 namespace expo {
instance()8 std::shared_ptr<JavaReferencesCache> JavaReferencesCache::instance() {
9 static std::shared_ptr<JavaReferencesCache> singleton{new JavaReferencesCache};
10 return singleton;
11 }
12
loadJClasses(JNIEnv * env)13 void JavaReferencesCache::loadJClasses(JNIEnv *env) {
14 loadJClass(env, "java/lang/Double", {
15 {"<init>", "(D)V"}
16 });
17
18 loadJClass(env, "java/lang/Boolean", {
19 {"<init>", "(Z)V"}
20 });
21
22 loadJClass(env, "java/lang/Integer", {
23 {"<init>", "(I)V"}
24 });
25
26 loadJClass(env, "java/lang/Long", {
27 {"<init>", "(J)V"}
28 });
29
30 loadJClass(env, "java/lang/Float", {
31 {"<init>", "(F)V"}
32 });
33
34 loadJClass(env, "com/facebook/react/bridge/PromiseImpl", {
35 {"<init>", "(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"}
36 });
37
38 loadJClass(env, "expo/modules/kotlin/jni/PromiseImpl", {
39 {"<init>", "(Lexpo/modules/kotlin/jni/JavaCallback;Lexpo/modules/kotlin/jni/JavaCallback;)V"}
40 });
41
42 loadJClass(env, "java/lang/Object", {});
43 loadJClass(env, "java/lang/String", {});
44 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptObject", {});
45 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptValue", {});
46 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptTypedArray", {});
47 loadJClass(env, "com/facebook/react/bridge/ReadableNativeArray", {});
48 loadJClass(env, "com/facebook/react/bridge/ReadableNativeMap", {});
49 loadJClass(env, "com/facebook/react/bridge/WritableNativeArray", {});
50 loadJClass(env, "com/facebook/react/bridge/WritableNativeMap", {});
51
52 loadJClass(env, "expo/modules/kotlin/sharedobjects/SharedObject", {});
53 }
54
loadJClass(JNIEnv * env,const std::string & name,const std::vector<std::pair<std::string,std::string>> & methodsNames)55 void JavaReferencesCache::loadJClass(
56 JNIEnv *env,
57 const std::string &name,
58 const std::vector<std::pair<std::string, std::string>> &methodsNames
59 ) {
60 // Note this clazz variable points to a leaked global reference.
61 // This is appropriate for classes that are never unloaded which is any class in an Android app.
62 auto clazz = (jclass) env->NewGlobalRef(env->FindClass(name.c_str()));
63
64 MethodHashMap methods;
65 methods.reserve(methodsNames.size());
66
67 for (auto &method: methodsNames) {
68 methods.insert(
69 {method, env->GetMethodID(clazz, method.first.c_str(), method.second.c_str())}
70 );
71 }
72
73 jClassRegistry.insert(
74 {name, CachedJClass(clazz, std::move(methods))}
75 );
76 }
77
getJClass(const std::string & className)78 JavaReferencesCache::CachedJClass &JavaReferencesCache::getJClass(
79 const std::string &className
80 ) {
81 return jClassRegistry.at(className);
82 }
83
getOrLoadJClass(JNIEnv * env,const std::string & className)84 JavaReferencesCache::CachedJClass &JavaReferencesCache::getOrLoadJClass(
85 JNIEnv *env,
86 const std::string &className
87 ) {
88 auto result = jClassRegistry.find(className);
89 if (result == jClassRegistry.end()) {
90 loadJClass(env, className, {});
91 return jClassRegistry.at(className);
92 }
93
94 return result->second;
95 }
96
getMethod(const std::string & name,const std::string & signature)97 jmethodID JavaReferencesCache::CachedJClass::getMethod(
98 const std::string &name,
99 const std::string &signature
100 ) {
101 return methods.at({name, signature});
102 }
103
CachedJClass(jclass clazz,MethodHashMap methods)104 JavaReferencesCache::CachedJClass::CachedJClass(
105 jclass clazz,
106 MethodHashMap methods
107 ) : clazz(clazz), methods(std::move(methods)) {}
108 } // namespace expo
109