mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Introduce __nativeComponentRegistry__getNativeViewConfig (#37522)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37522 This diff adds cross-platform Cxx binding helper and iOS specific implementation of `__nativeComponentRegistry__getNativeViewConfig` to JS runtime. This function provides native view config for a native component in bridgeless mode. Changelog: [Internal] - Introduce `__nativeComponentRegistry__getNativeViewConfig` in iOS. Reviewed By: javache Differential Revision: D43538804 fbshipit-source-id: 0aeca40c1c2a625eca5d60e466eb24df30453ba7
This commit is contained in:
committed by
Facebook GitHub Bot
parent
da3dcd7326
commit
7f22db8ea0
@@ -81,3 +81,9 @@ RCT_EXTERN void RCTSetMemoryPressureUnloadLevel(int value);
|
||||
*/
|
||||
RCT_EXTERN BOOL RCTGetParseUnhandledJSErrorStackNatively(void);
|
||||
RCT_EXTERN void RCTSetParseUnhandledJSErrorStackNatively(BOOL value);
|
||||
|
||||
/*
|
||||
* Use native view configs in bridgeless mode
|
||||
*/
|
||||
RCT_EXTERN BOOL RCTGetUseNativeViewConfigsInBridgelessMode(void);
|
||||
RCT_EXTERN void RCTSetUseNativeViewConfigsInBridgelessMode(BOOL value);
|
||||
|
||||
@@ -81,3 +81,18 @@ void RCTSetParseUnhandledJSErrorStackNatively(BOOL value)
|
||||
{
|
||||
RCTParseUnhandledJSErrorStackNatively = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use native view configs in bridgeless mode
|
||||
*/
|
||||
static BOOL RCTUseNativeViewConfigsInBridgelessMode = NO;
|
||||
|
||||
BOOL RCTGetUseNativeViewConfigsInBridgelessMode(void)
|
||||
{
|
||||
return RCTUseNativeViewConfigsInBridgelessMode;
|
||||
}
|
||||
|
||||
void RCTSetUseNativeViewConfigsInBridgelessMode(BOOL value)
|
||||
{
|
||||
RCTUseNativeViewConfigsInBridgelessMode = value;
|
||||
}
|
||||
|
||||
@@ -172,3 +172,10 @@ RCT_EXTERN NSString *const RCTUIManagerWillUpdateViewsDueToContentSizeMultiplier
|
||||
@property (nonatomic, readonly) RCTUIManager *uiManager;
|
||||
|
||||
@end
|
||||
|
||||
RCT_EXTERN NSMutableDictionary<NSString *, id> *RCTModuleConstantsForDestructuredComponent(
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,
|
||||
Class managerClass,
|
||||
NSString *name,
|
||||
NSDictionary<NSString *, id> *viewConfig);
|
||||
|
||||
@@ -1463,10 +1463,12 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
||||
}];
|
||||
}
|
||||
|
||||
static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
NSMutableDictionary<NSString *, id> *RCTModuleConstantsForDestructuredComponent(
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,
|
||||
RCTComponentData *componentData)
|
||||
Class managerClass,
|
||||
NSString *name,
|
||||
NSDictionary<NSString *, id> *viewConfig)
|
||||
{
|
||||
NSMutableDictionary<NSString *, id> *moduleConstants = [NSMutableDictionary new];
|
||||
|
||||
@@ -1476,10 +1478,9 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *directEventTypes = [NSMutableDictionary new];
|
||||
|
||||
// Add manager class
|
||||
moduleConstants[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass);
|
||||
moduleConstants[@"Manager"] = RCTBridgeModuleNameForClass(managerClass);
|
||||
|
||||
// Add native props
|
||||
NSDictionary<NSString *, id> *viewConfig = [componentData viewConfig];
|
||||
moduleConstants[@"NativeProps"] = viewConfig[@"propTypes"];
|
||||
moduleConstants[@"baseModuleName"] = viewConfig[@"baseModuleName"];
|
||||
moduleConstants[@"bubblingEventTypes"] = bubblingEventTypes;
|
||||
@@ -1497,7 +1498,7 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
RCTLogError(
|
||||
@"Component '%@' re-registered bubbling event '%@' as a "
|
||||
"direct event",
|
||||
componentData.name,
|
||||
name,
|
||||
eventName);
|
||||
}
|
||||
}
|
||||
@@ -1518,7 +1519,7 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
RCTLogError(
|
||||
@"Component '%@' re-registered direct event '%@' as a "
|
||||
"bubbling event",
|
||||
componentData.name,
|
||||
name,
|
||||
eventName);
|
||||
}
|
||||
}
|
||||
@@ -1540,7 +1541,7 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
RCTLogError(
|
||||
@"Component '%@' re-registered direct event '%@' as a "
|
||||
"bubbling event",
|
||||
componentData.name,
|
||||
name,
|
||||
eventName);
|
||||
}
|
||||
}
|
||||
@@ -1548,6 +1549,15 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
return moduleConstants;
|
||||
}
|
||||
|
||||
static NSMutableDictionary<NSString *, id> *moduleConstantsForComponentData(
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,
|
||||
RCTComponentData *componentData)
|
||||
{
|
||||
return RCTModuleConstantsForDestructuredComponent(
|
||||
directEvents, bubblingEvents, componentData.managerClass, componentData.name, componentData.viewConfig);
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
return [self getConstants];
|
||||
@@ -1563,7 +1573,7 @@ static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
|
||||
enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) {
|
||||
RCTAssert(!constants[name], @"UIManager already has constants for %@", componentData.name);
|
||||
NSMutableDictionary<NSString *, id> *moduleConstants =
|
||||
moduleConstantsForComponent(directEvents, bubblingEvents, componentData);
|
||||
moduleConstantsForComponentData(directEvents, bubblingEvents, componentData);
|
||||
constants[name] = moduleConstants;
|
||||
}];
|
||||
|
||||
@@ -1611,7 +1621,7 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(lazilyLoadView : (NSString *)name)
|
||||
NSMutableDictionary *directEvents = [NSMutableDictionary new];
|
||||
NSMutableDictionary *bubblingEvents = [NSMutableDictionary new];
|
||||
NSMutableDictionary<NSString *, id> *moduleConstants =
|
||||
moduleConstantsForComponent(directEvents, bubblingEvents, componentData);
|
||||
moduleConstantsForComponentData(directEvents, bubblingEvents, componentData);
|
||||
return @{
|
||||
@"viewConfig" : moduleConstants,
|
||||
};
|
||||
|
||||
@@ -42,8 +42,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, copy, nullable) void (^eventInterceptor)
|
||||
(NSString *eventName, NSDictionary *event, NSNumber *reactTag);
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)viewConfigForViewMangerClass:(Class)managerClass;
|
||||
- (NSDictionary<NSString *, id> *)viewConfig;
|
||||
|
||||
@end
|
||||
|
||||
RCT_EXTERN NSString *RCTViewManagerModuleNameForClass(Class managerClass);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -55,7 +55,7 @@ static SEL selectorForType(NSString *type)
|
||||
_viewPropBlocks = [NSMutableDictionary new];
|
||||
_shadowPropBlocks = [NSMutableDictionary new];
|
||||
|
||||
_name = moduleNameForClass(managerClass);
|
||||
_name = RCTViewManagerModuleNameForClass(managerClass);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -385,7 +385,7 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)viewConfig
|
||||
+ (NSDictionary<NSString *, id> *)viewConfigForViewMangerClass:(Class)managerClass
|
||||
{
|
||||
NSMutableArray<NSString *> *bubblingEvents = [NSMutableArray new];
|
||||
NSMutableArray<NSString *> *capturingEvents = [NSMutableArray new];
|
||||
@@ -393,8 +393,8 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customBubblingEventTypes))) {
|
||||
NSArray<NSString *> *events = [self.manager customBubblingEventTypes];
|
||||
if (RCTClassOverridesInstanceMethod(managerClass, @selector(customBubblingEventTypes))) {
|
||||
NSArray<NSString *> *events = [[managerClass new] customBubblingEventTypes];
|
||||
for (NSString *event in events) {
|
||||
[bubblingEvents addObject:RCTNormalizeInputEventName(event)];
|
||||
}
|
||||
@@ -403,7 +403,7 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
|
||||
|
||||
unsigned int count = 0;
|
||||
NSMutableDictionary *propTypes = [NSMutableDictionary new];
|
||||
Method *methods = class_copyMethodList(object_getClass(_managerClass), &count);
|
||||
Method *methods = class_copyMethodList(object_getClass(managerClass), &count);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
SEL selector = method_getName(methods[i]);
|
||||
const char *selectorName = sel_getName(selector);
|
||||
@@ -418,13 +418,13 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
|
||||
}
|
||||
|
||||
NSString *name = @(underscorePos + 1);
|
||||
NSString *type = ((NSArray<NSString *> * (*)(id, SEL)) objc_msgSend)(_managerClass, selector)[0];
|
||||
NSString *type = ((NSArray<NSString *> * (*)(id, SEL)) objc_msgSend)(managerClass, selector)[0];
|
||||
if (RCT_DEBUG && propTypes[name] && ![propTypes[name] isEqualToString:type]) {
|
||||
RCTLogError(
|
||||
@"Property '%@' of component '%@' redefined from '%@' "
|
||||
"to '%@'",
|
||||
name,
|
||||
_name,
|
||||
RCTViewManagerModuleNameForClass(managerClass),
|
||||
propTypes[name],
|
||||
type);
|
||||
}
|
||||
@@ -450,24 +450,31 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
|
||||
RCTLogError(
|
||||
@"Component '%@' registered '%@' as both a bubbling event "
|
||||
"and a direct event",
|
||||
_name,
|
||||
RCTViewManagerModuleNameForClass(managerClass),
|
||||
event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Class superClass = [_managerClass superclass];
|
||||
Class superClass = [managerClass superclass];
|
||||
|
||||
return @{
|
||||
@"propTypes" : propTypes,
|
||||
@"directEvents" : directEvents,
|
||||
@"bubblingEvents" : bubblingEvents,
|
||||
@"capturingEvents" : capturingEvents,
|
||||
@"baseModuleName" : superClass == [NSObject class] ? (id)kCFNull : moduleNameForClass(superClass),
|
||||
@"baseModuleName" : superClass == [NSObject class] ? (id)kCFNull : RCTViewManagerModuleNameForClass(superClass),
|
||||
};
|
||||
}
|
||||
|
||||
static NSString *moduleNameForClass(Class managerClass)
|
||||
- (NSDictionary<NSString *, id> *)viewConfig
|
||||
{
|
||||
// Make sure the manager is initialized before accessing view config.
|
||||
[self manager];
|
||||
return [RCTComponentData viewConfigForViewMangerClass:_managerClass];
|
||||
}
|
||||
|
||||
NSString *RCTViewManagerModuleNameForClass(Class managerClass)
|
||||
{
|
||||
// Hackety hack, this partially re-implements RCTBridgeModuleNameForClass
|
||||
// We want to get rid of RCT and RK prefixes, but a lot of JS code still references
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 "NativeViewConfigProviderBinding.h"
|
||||
|
||||
namespace facebook::react::NativeViewConfigProviderBinding {
|
||||
|
||||
void install(jsi::Runtime &runtime, ProviderType &&provider) {
|
||||
auto name = "RN$NativeComponentRegistry_getNativeViewConfig";
|
||||
auto hostFunction = [provider = std::move(provider)](
|
||||
jsi::Runtime &runtime,
|
||||
jsi::Value const & /*thisValue*/,
|
||||
jsi::Value const *args,
|
||||
size_t count) -> jsi::Value {
|
||||
if (count != 1 || !args[0].isString()) {
|
||||
throw new jsi::JSError(runtime, "1 argument of type String expected.");
|
||||
}
|
||||
return provider(args[0].getString(runtime).utf8(runtime));
|
||||
};
|
||||
|
||||
auto jsiFunction = jsi::Function::createFromHostFunction(
|
||||
runtime, jsi::PropNameID::forAscii(runtime, name), 2, hostFunction);
|
||||
|
||||
runtime.global().setProperty(runtime, name, jsiFunction);
|
||||
}
|
||||
} // namespace facebook::react::NativeViewConfigProviderBinding
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 <jsi/jsi.h>
|
||||
|
||||
namespace facebook::react::NativeViewConfigProviderBinding {
|
||||
|
||||
using ProviderType = std::function<jsi::Value(const std::string &name)>;
|
||||
|
||||
/*
|
||||
* Installs native view config provider into JavaScript runtime.
|
||||
*/
|
||||
void install(jsi::Runtime &runtime, ProviderType &&provider);
|
||||
} // namespace facebook::react::NativeViewConfigProviderBinding
|
||||
@@ -14,6 +14,7 @@
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTBridgeModuleDecorator.h>
|
||||
#import <React/RCTComponentViewFactory.h>
|
||||
#import <React/RCTConstants.h>
|
||||
#import <React/RCTCxxUtils.h>
|
||||
#import <React/RCTDevSettings.h>
|
||||
#import <React/RCTDisplayLink.h>
|
||||
@@ -25,6 +26,7 @@
|
||||
#import <React/RCTModuleData.h>
|
||||
#import <React/RCTPerformanceLogger.h>
|
||||
#import <React/RCTSurfacePresenter.h>
|
||||
#import <ReactCommon/RCTNativeViewConfigProvider.h>
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
#import <ReactCommon/RuntimeExecutor.h>
|
||||
#import <cxxreact/ReactMarker.h>
|
||||
@@ -283,6 +285,10 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags)
|
||||
});
|
||||
RCTInstallNativeComponentRegistryBinding(runtime);
|
||||
|
||||
if (RCTGetUseNativeViewConfigsInBridgelessMode()) {
|
||||
installNativeViewConfigProviderBinding(runtime);
|
||||
}
|
||||
|
||||
if (strongSelf->_bindingsInstallFunc) {
|
||||
strongSelf->_bindingsInstallFunc(runtime);
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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 <jsi/jsi.h>
|
||||
|
||||
namespace facebook::react {
|
||||
/*
|
||||
* Installs native view config provider into JavaScript runtime.
|
||||
*/
|
||||
void installNativeViewConfigProviderBinding(jsi::Runtime &runtime);
|
||||
} // namespace facebook::react
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 <React/RCTBridge+Private.h>
|
||||
#import <React/RCTComponentData.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTViewManager.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
#import <react/bridgeless/nativeviewconfig/NativeViewConfigProviderBinding.h>
|
||||
|
||||
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<NSString *, NSObject *> *eagerViewConfigs()
|
||||
{
|
||||
static NSMutableDictionary<NSString *, NSObject *> *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
|
||||
Reference in New Issue
Block a user