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/Long", { 25 {"<init>", "(J)V"} 26 }); 27 28 loadJClass(env, "java/lang/Float", { 29 {"<init>", "(F)V"} 30 }); 31 32 loadJClass(env, "com/facebook/react/bridge/PromiseImpl", { 33 {"<init>", "(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"} 34 }); 35 36 loadJClass(env, "expo/modules/kotlin/jni/PromiseImpl", { 37 {"<init>", "(Lexpo/modules/kotlin/jni/JavaCallback;Lexpo/modules/kotlin/jni/JavaCallback;)V"} 38 }); 39 40 loadJClass(env, "java/lang/Object", {}); 41 loadJClass(env, "java/lang/String", {}); 42 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptObject", {}); 43 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptValue", {}); 44 loadJClass(env, "expo/modules/kotlin/jni/JavaScriptTypedArray", {}); 45 loadJClass(env, "com/facebook/react/bridge/ReadableNativeArray", {}); 46 loadJClass(env, "com/facebook/react/bridge/ReadableNativeMap", {}); 47 loadJClass(env, "com/facebook/react/bridge/WritableNativeArray", {}); 48 loadJClass(env, "com/facebook/react/bridge/WritableNativeMap", {}); 49 } 50 51 void JavaReferencesCache::loadJClass( 52 JNIEnv *env, 53 const std::string &name, 54 const std::vector<std::pair<std::string, std::string>> &methodsNames 55 ) { 56 // Note this clazz variable points to a leaked global reference. 57 // This is appropriate for classes that are never unloaded which is any class in an Android app. 58 auto clazz = (jclass) env->NewGlobalRef(env->FindClass(name.c_str())); 59 60 MethodHashMap methods; 61 methods.reserve(methodsNames.size()); 62 63 for (auto &method: methodsNames) { 64 methods.insert( 65 {method, env->GetMethodID(clazz, method.first.c_str(), method.second.c_str())} 66 ); 67 } 68 69 jClassRegistry.insert( 70 {name, CachedJClass(clazz, std::move(methods))} 71 ); 72 } 73 74 JavaReferencesCache::CachedJClass &JavaReferencesCache::getJClass( 75 const std::string &className 76 ) { 77 return jClassRegistry.at(className); 78 } 79 80 JavaReferencesCache::CachedJClass &JavaReferencesCache::getOrLoadJClass( 81 JNIEnv *env, 82 const std::string &className 83 ) { 84 auto result = jClassRegistry.find(className); 85 if (result == jClassRegistry.end()) { 86 loadJClass(env, className, {}); 87 return jClassRegistry.at(className); 88 } 89 90 return result->second; 91 } 92 93 jmethodID JavaReferencesCache::CachedJClass::getMethod( 94 const std::string &name, 95 const std::string &signature 96 ) { 97 return methods.at({name, signature}); 98 } 99 100 JavaReferencesCache::CachedJClass::CachedJClass( 101 jclass clazz, 102 MethodHashMap methods 103 ) : clazz(clazz), methods(std::move(methods)) {} 104 } // namespace expo 105