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