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 53 void JavaReferencesCache::loadJClass( 54 JNIEnv *env, 55 const std::string &name, 56 const std::vector<std::pair<std::string, std::string>> &methodsNames 57 ) { 58 // Note this clazz variable points to a leaked global reference. 59 // This is appropriate for classes that are never unloaded which is any class in an Android app. 60 auto clazz = (jclass) env->NewGlobalRef(env->FindClass(name.c_str())); 61 62 MethodHashMap methods; 63 methods.reserve(methodsNames.size()); 64 65 for (auto &method: methodsNames) { 66 methods.insert( 67 {method, env->GetMethodID(clazz, method.first.c_str(), method.second.c_str())} 68 ); 69 } 70 71 jClassRegistry.insert( 72 {name, CachedJClass(clazz, std::move(methods))} 73 ); 74 } 75 76 JavaReferencesCache::CachedJClass &JavaReferencesCache::getJClass( 77 const std::string &className 78 ) { 79 return jClassRegistry.at(className); 80 } 81 82 JavaReferencesCache::CachedJClass &JavaReferencesCache::getOrLoadJClass( 83 JNIEnv *env, 84 const std::string &className 85 ) { 86 auto result = jClassRegistry.find(className); 87 if (result == jClassRegistry.end()) { 88 loadJClass(env, className, {}); 89 return jClassRegistry.at(className); 90 } 91 92 return result->second; 93 } 94 95 jmethodID JavaReferencesCache::CachedJClass::getMethod( 96 const std::string &name, 97 const std::string &signature 98 ) { 99 return methods.at({name, signature}); 100 } 101 102 JavaReferencesCache::CachedJClass::CachedJClass( 103 jclass clazz, 104 MethodHashMap methods 105 ) : clazz(clazz), methods(std::move(methods)) {} 106 } // namespace expo 107