1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #include "JavaReferencesCache.h" 4 5 #include <vector> 6 7 namespace expo { 8 std::shared_ptr<JavaReferencesCache> JavaReferencesCache::instance() { 9 static std::shared_ptr<JavaReferencesCache> singleton{new JavaReferencesCache}; 10 return singleton; 11 } 12 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 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 78 JavaReferencesCache::CachedJClass &JavaReferencesCache::getJClass( 79 const std::string &className 80 ) { 81 return jClassRegistry.at(className); 82 } 83 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 97 jmethodID JavaReferencesCache::CachedJClass::getMethod( 98 const std::string &name, 99 const std::string &signature 100 ) { 101 return methods.at({name, signature}); 102 } 103 104 JavaReferencesCache::CachedJClass::CachedJClass( 105 jclass clazz, 106 MethodHashMap methods 107 ) : clazz(clazz), methods(std::move(methods)) {} 108 } // namespace expo 109