diff --git a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index c5f5aca5f382e1..dec251ef14e39d 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -16,7 +16,7 @@ namespace facebook { namespace react { -static jsi::Object getModule( +static jsi::Value getModule( jsi::Runtime &runtime, std::string const &moduleName) { auto batchedBridge = @@ -31,7 +31,30 @@ static jsi::Object getModule( LOG(ERROR) << "getModule of " << moduleName << " is not an object"; } react_native_assert(moduleAsValue.isObject()); - return moduleAsValue.asObject(runtime); + return moduleAsValue; +} + +static bool checkBatchedBridgeIsActive(jsi::Runtime &runtime) { + if (!runtime.global().hasProperty(runtime, "__fbBatchedBridge")) { + LOG(ERROR) + << "getPropertyAsObject: property '__fbBatchedBridge' is undefined, expected an Object"; + return false; + } + return true; +} + +static bool checkGetCallableModuleIsActive(jsi::Runtime &runtime) { + if (!checkBatchedBridgeIsActive(runtime)) { + return false; + } + auto batchedBridge = + runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge"); + if (!batchedBridge.hasProperty(runtime, "getCallableModule")) { + LOG(ERROR) + << "getPropertyAsFunction: function 'getCallableModule' is undefined, expected a Function"; + return false; + } + return true; } std::shared_ptr UIManagerBinding::createAndInstallIfNeeded( @@ -94,6 +117,27 @@ void UIManagerBinding::attach(std::shared_ptr const &uiManager) { } } +static void callMethodOfModule( + jsi::Runtime &runtime, + std::string const &moduleName, + std::string const &methodName, + std::initializer_list args) { + if (checkGetCallableModuleIsActive(runtime)) { + auto module = getModule(runtime, moduleName.c_str()); + if (module.isObject()) { + jsi::Object object = module.asObject(runtime); + react_native_assert(object.hasProperty(runtime, methodName.c_str())); + if (object.hasProperty(runtime, methodName.c_str())) { + auto method = object.getPropertyAsFunction(runtime, methodName.c_str()); + method.callWithThis(runtime, object, args); + } else { + LOG(ERROR) << "getPropertyAsFunction: property '" << methodName + << "' is undefined, expected a Function"; + } + } + } +} + void UIManagerBinding::startSurface( jsi::Runtime &runtime, SurfaceId surfaceId, @@ -115,12 +159,10 @@ void UIManagerBinding::startSurface( {jsi::String::createFromUtf8(runtime, moduleName), jsi::valueFromDynamic(runtime, parameters)}); } else { - auto module = getModule(runtime, "AppRegistry"); - auto method = module.getPropertyAsFunction(runtime, "runApplication"); - - method.callWithThis( + callMethodOfModule( runtime, - module, + "AppRegistry", + "runApplication", {jsi::String::createFromUtf8(runtime, moduleName), jsi::valueFromDynamic(runtime, parameters)}); } @@ -129,20 +171,17 @@ void UIManagerBinding::startSurface( void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) const { auto global = runtime.global(); - if (global.hasProperty(runtime, "RN$Bridgeless")) { - if (!global.hasProperty(runtime, "RN$stopSurface")) { - // ReactFabric module has not been loaded yet; there's no surface to stop. - return; - } + if (global.hasProperty(runtime, "RN$Bridgeless") && + global.hasProperty(runtime, "RN$stopSurface")) { // Bridgeless mode uses a custom JSI binding instead of callable module. global.getPropertyAsFunction(runtime, "RN$stopSurface") .call(runtime, {jsi::Value{surfaceId}}); } else { - auto module = getModule(runtime, "ReactFabric"); - auto method = - module.getPropertyAsFunction(runtime, "unmountComponentAtNode"); - - method.callWithThis(runtime, module, {jsi::Value{surfaceId}}); + callMethodOfModule( + runtime, + "ReactFabric", + "unmountComponentAtNode", + {jsi::Value{surfaceId}}); } }