1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #include "ExpoModulesHostObject.h" 4 #include "LazyObject.h" 5 6 #include <folly/dynamic.h> 7 #include <jsi/JSIDynamic.h> 8 #include <react/bridging/LongLivedObject.h> 9 10 namespace jsi = facebook::jsi; 11 12 namespace expo { 13 14 ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer) 15 : installer(installer) {} 16 17 /** 18 * Clears jsi references held by JSRegistry and JavaScriptRuntime. 19 */ 20 ExpoModulesHostObject::~ExpoModulesHostObject() { 21 facebook::react::LongLivedObjectCollection::get().clear(); 22 installer->jsRegistry.reset(); 23 installer->runtimeHolder.reset(); 24 installer->jsInvoker.reset(); 25 installer->nativeInvoker.reset(); 26 installer->jniDeallocator.reset(); 27 } 28 29 jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) { 30 auto cName = name.utf8(runtime); 31 32 if (!installer->hasModule(cName)) { 33 modulesCache.erase(cName); 34 return jsi::Value::undefined(); 35 } 36 if (UniqueJSIObject &cachedObject = modulesCache[cName]) { 37 return jsi::Value(runtime, *cachedObject); 38 } 39 40 // Create a lazy object for the specific module. It defers initialization of the final module object. 41 LazyObject::Shared moduleLazyObject = std::make_shared<LazyObject>( 42 [this, cName](jsi::Runtime &rt) { 43 auto module = installer->getModule(cName); 44 module->cthis()->jsiInteropModuleRegistry = installer; 45 return module->cthis()->getJSIObject(rt); 46 }); 47 48 // Save the module's lazy host object for later use. 49 modulesCache[cName] = std::make_unique<jsi::Object>( 50 jsi::Object::createFromHostObject(runtime, moduleLazyObject)); 51 52 return jsi::Value(runtime, *modulesCache[cName]); 53 } 54 55 void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name, 56 const jsi::Value &value) { 57 throw jsi::JSError( 58 runtime, 59 "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'" 60 ); 61 } 62 63 std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &rt) { 64 auto names = installer->getModulesName(); 65 size_t size = names->size(); 66 std::vector<jsi::PropNameID> result; 67 result.reserve(size); 68 for (int i = 0; i < size; i++) { 69 result.push_back( 70 jsi::PropNameID::forUtf8(rt, names->getElement(i)->toStdString()) 71 ); 72 } 73 return result; 74 } 75 } // namespace expo 76