From 354cda7216fe3191dba2f7a2483a33350d8c608b Mon Sep 17 00:00:00 2001 From: Dmitry Rykun Date: Wed, 28 Jun 2023 03:04:11 -0700 Subject: [PATCH] Expose UIManager.getConstants instead of getNativeViewConfig to JS in bridgeless mode (#37865) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37865 In bridge mode UIManager's `constants` contain view configs for every registered native component and possibly some extra data. On iOS there is no extra data, but on Android in addition to view configs there are `genericBubblingEventTypes` and `genericDirectEventTypes`. They are then [merged](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/ReactNative/getNativeComponentAttributes.js#L110-L116) into `bubblingEventTypes` and `directEventTypes` of every view config. This diff replaces `getNativeViewConfig` binding with `getConstants` to make this behaviour possible in the bridgeless mode. This diff also removes caching on native side with the expectation that `constants` will be cached on JS side just as [it is done](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/ReactNative/PaperUIManager.js#L24-L32) in bridge mode. Changelog: [Internal] - Expose UIManager.getConstants instead of getNativeViewConfig to JS in bridgeless mode. Reviewed By: RSNara Differential Revision: D46698717 fbshipit-source-id: a42d232ed131c0f6dbd6901dc262d5931fb8e6e4 --- ...gacyUIManagerConstantsProviderBinding.cpp} | 16 ++--- .../LegacyUIManagerConstantsProviderBinding.h | 22 +++++++ .../NativeViewConfigProviderBinding.h | 20 ------- .../platform/ios/Core/RCTInstance.mm | 4 +- .../RCTLegacyUIManagerConstantsProvider.h | 19 ++++++ .../RCTLegacyUIManagerConstantsProvider.mm | 44 ++++++++++++++ .../RCTNativeViewConfigProvider.h | 17 ------ .../RCTNativeViewConfigProvider.mm | 58 ------------------- 8 files changed, 95 insertions(+), 105 deletions(-) rename packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/{NativeViewConfigProviderBinding.cpp => LegacyUIManagerConstantsProviderBinding.cpp} (59%) create mode 100644 packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.h delete mode 100644 packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.h create mode 100644 packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.h create mode 100644 packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.mm delete mode 100644 packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.h delete mode 100644 packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.mm diff --git a/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.cpp b/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.cpp similarity index 59% rename from packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.cpp rename to packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.cpp index d29eca015d1087..f3b1eb8ffed96f 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.cpp +++ b/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.cpp @@ -5,21 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -#include "NativeViewConfigProviderBinding.h" +#include "LegacyUIManagerConstantsProviderBinding.h" -namespace facebook::react::NativeViewConfigProviderBinding { +namespace facebook::react::LegacyUIManagerConstantsProviderBinding { void install(jsi::Runtime &runtime, ProviderType &&provider) { - auto name = "RN$NativeComponentRegistry_getNativeViewConfig"; + auto name = "RN$LegacyInterop_UIManager_getConstants"; auto hostFunction = [provider = std::move(provider)]( jsi::Runtime &runtime, jsi::Value const & /*thisValue*/, - jsi::Value const *args, + jsi::Value const * /*arguments*/, size_t count) -> jsi::Value { - if (count != 1 || !args[0].isString()) { - throw new jsi::JSError(runtime, "1 argument of type String expected."); + if (count != 0) { + throw new jsi::JSError(runtime, "0 arguments expected."); } - return provider(args[0].getString(runtime).utf8(runtime)); + return provider(); }; auto jsiFunction = jsi::Function::createFromHostFunction( @@ -27,4 +27,4 @@ void install(jsi::Runtime &runtime, ProviderType &&provider) { runtime.global().setProperty(runtime, name, jsiFunction); } -} // namespace facebook::react::NativeViewConfigProviderBinding +} // namespace facebook::react::LegacyUIManagerConstantsProviderBinding diff --git a/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.h b/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.h new file mode 100644 index 00000000000000..b32cc7c8f23fe4 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react::LegacyUIManagerConstantsProviderBinding { + +using ProviderType = std::function; + +/* + * Installs RN$LegacyInterop_UIManager_getConstants binding into JavaScript + * runtime. It is supposed to be used as a substitute to UIManager.getConstants + * in bridgeless mode. + */ +void install(jsi::Runtime &runtime, ProviderType &&provider); +} // namespace facebook::react::LegacyUIManagerConstantsProviderBinding diff --git a/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.h b/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.h deleted file mode 100644 index b635eab8777117..00000000000000 --- a/packages/react-native/ReactCommon/react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -namespace facebook::react::NativeViewConfigProviderBinding { - -using ProviderType = std::function; - -/* - * Installs native view config provider into JavaScript runtime. - */ -void install(jsi::Runtime &runtime, ProviderType &&provider); -} // namespace facebook::react::NativeViewConfigProviderBinding diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm index a2af2f7afd4c2d..4dd5528934dd04 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm @@ -28,7 +28,7 @@ #import #import #import -#import +#import #import #import #import @@ -296,7 +296,7 @@ - (void)_start RCTInstallNativeComponentRegistryBinding(runtime); if (RCTGetUseNativeViewConfigsInBridgelessMode()) { - installNativeViewConfigProviderBinding(runtime); + installLegacyUIManagerConstantsProviderBinding(runtime); } [strongSelf->_delegate instance:strongSelf didInitializeRuntime:runtime]; diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.h new file mode 100644 index 00000000000000..9359df209c0494 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react { +/* + * Installs UIManger constants provider into JavaScript runtime. This is needed + * to implement UIManager.getConstants in bridgeless mode. The constants object + * contains view configs for every legacy native component. + */ +void installLegacyUIManagerConstantsProviderBinding(jsi::Runtime &runtime); +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.mm new file mode 100644 index 00000000000000..b156a127994ca6 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTLegacyUIManagerConstantsProvider.mm @@ -0,0 +1,44 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "RCTLegacyUIManagerConstantsProvider.h" + +#import +#import +#import +#import +#import +#import + +namespace facebook::react { +namespace { + +jsi::Value getConstants(facebook::jsi::Runtime &runtime) +{ + static NSMutableDictionary *result = [NSMutableDictionary new]; + auto directEvents = [NSMutableDictionary new]; + auto bubblingEvents = [NSMutableDictionary new]; + for (Class moduleClass in RCTGetModuleClasses()) { + if ([moduleClass isSubclassOfClass:RCTViewManager.class]) { + auto name = RCTViewManagerModuleNameForClass(moduleClass); + auto viewConfig = [RCTComponentData viewConfigForViewMangerClass:moduleClass]; + auto moduleConstants = + RCTModuleConstantsForDestructuredComponent(directEvents, bubblingEvents, moduleClass, name, viewConfig); + result[name] = moduleConstants; + } + } + return TurboModuleConvertUtils::convertObjCObjectToJSIValue(runtime, result); +}; + +} // namespace + +void installLegacyUIManagerConstantsProviderBinding(jsi::Runtime &runtime) +{ + auto constantsProvider = [&runtime]() -> jsi::Value { return getConstants(runtime); }; + LegacyUIManagerConstantsProviderBinding::install(runtime, std::move(constantsProvider)); +} +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.h deleted file mode 100644 index 2f5c555581a294..00000000000000 --- a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -namespace facebook::react { -/* - * Installs native view config provider into JavaScript runtime. - */ -void installNativeViewConfigProviderBinding(jsi::Runtime &runtime); -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.mm deleted file mode 100644 index 97108934347076..00000000000000 --- a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/NativeViewConfig/RCTNativeViewConfigProvider.mm +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "RCTNativeViewConfigProvider.h" - -#import -#import -#import -#import -#import -#import - -namespace facebook::react { -namespace { - -// This function eagerly loads module constants for every RCTViewManager subclass. -// This is not compatible with lazily loaded modules, but we don't have them in OSS, so that's fine for now. -NSDictionary *eagerViewConfigs() -{ - static NSMutableDictionary *result = [NSMutableDictionary new]; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - auto directEvents = [NSMutableDictionary new]; - auto bubblingEvents = [NSMutableDictionary new]; - for (Class moduleClass in RCTGetModuleClasses()) { - if ([moduleClass isSubclassOfClass:RCTViewManager.class]) { - auto name = RCTViewManagerModuleNameForClass(moduleClass); - auto viewConfig = [RCTComponentData viewConfigForViewMangerClass:moduleClass]; - auto moduleConstants = - RCTModuleConstantsForDestructuredComponent(directEvents, bubblingEvents, moduleClass, name, viewConfig); - result[name] = moduleConstants; - } - } - }); - return result; -} - -jsi::Value provideNativeViewConfig(facebook::jsi::Runtime &runtime, std::string const &name) -{ - auto componentName = [NSString stringWithCString:name.c_str() encoding:NSASCIIStringEncoding]; - auto viewConfig = eagerViewConfigs()[componentName]; - return TurboModuleConvertUtils::convertObjCObjectToJSIValue(runtime, viewConfig); -}; - -} // namespace - -void installNativeViewConfigProviderBinding(jsi::Runtime &runtime) -{ - auto nativeViewConfigProvider = [&runtime](std::string const &name) -> jsi::Value { - return provideNativeViewConfig(runtime, name); - }; - NativeViewConfigProviderBinding::install(runtime, std::move(nativeViewConfigProvider)); -} -} // namespace facebook::react