diff --git a/packages/react-native/React/Modules/RCTUIManager.m b/packages/react-native/React/Modules/RCTUIManager.m index 6f03df143f1..209c1326e00 100644 --- a/packages/react-native/React/Modules/RCTUIManager.m +++ b/packages/react-native/React/Modules/RCTUIManager.m @@ -1485,6 +1485,13 @@ NSMutableDictionary *RCTModuleConstantsForDestructuredComponent( moduleConstants[@"baseModuleName"] = viewConfig[@"baseModuleName"]; moduleConstants[@"bubblingEventTypes"] = bubblingEventTypes; moduleConstants[@"directEventTypes"] = directEventTypes; + // In the Old Architecture the "Commands" and "Constants" properties of view manager config are populated by + // lazifyViewManagerConfig function in JS. This fuction uses NativeModules global object that is not available in the + // New Architecture. To make native view configs work in the New Architecture we will populate these properties in + // native. + moduleConstants[@"Commands"] = viewConfig[@"Commands"]; + // In the Old Architecture "Constants" are empty. + moduleConstants[@"Constants"] = [NSDictionary new]; // Add direct events for (NSString *eventName in viewConfig[@"directEvents"]) { diff --git a/packages/react-native/React/Views/RCTComponentData.m b/packages/react-native/React/Views/RCTComponentData.m index 94b30a63480..da9f8206138 100644 --- a/packages/react-native/React/Views/RCTComponentData.m +++ b/packages/react-native/React/Views/RCTComponentData.m @@ -15,6 +15,7 @@ #import "RCTConstants.h" #import "RCTConvert.h" #import "RCTEventDispatcherProtocol.h" +#import "RCTModuleMethod.h" #import "RCTParserUtils.h" #import "RCTShadowView.h" #import "RCTUtils.h" @@ -385,6 +386,34 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S }]; } ++ (NSDictionary *)commandsForViewMangerClass:(Class)managerClass + methods:(Method *)methods + methodCount:(unsigned int)methodCount +{ + NSMutableDictionary *commands = [NSMutableDictionary new]; + static const char *prefix = "__rct_export__"; + const unsigned int prefixLength = strlen(prefix); + int commandCount = 0; + for (int i = 0; i < methodCount; i++) { + SEL selector = method_getName(methods[i]); + const char *selectorName = sel_getName(selector); + if (strncmp(selectorName, prefix, prefixLength) != 0) { + continue; + } + RCTMethodInfo *methodInfo = ((RCTMethodInfo * (*)(id, SEL)) objc_msgSend)(managerClass, selector); + RCTModuleMethod *moduleMethod = [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo + moduleClass:managerClass]; + NSString *methodName = @(moduleMethod.JSMethodName); + commands[methodName] = @(commandCount); + commandCount += 1; + } + // View manager do not export getConstants with RCT_EXPORT_METHOD, so we inject it into "Commands" manually. + if (commandCount > 0) { + commands[@"getConstants"] = @(commandCount); + } + return commands; +} + + (NSDictionary *)viewConfigForViewMangerClass:(Class)managerClass { NSMutableArray *bubblingEvents = [NSMutableArray new]; @@ -442,6 +471,10 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S propTypes[name] = type; } } + + NSDictionary *commands = [self commandsForViewMangerClass:managerClass + methods:methods + methodCount:count]; free(methods); #if RCT_DEBUG @@ -464,6 +497,7 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S @"bubblingEvents" : bubblingEvents, @"capturingEvents" : capturingEvents, @"baseModuleName" : superClass == [NSObject class] ? (id)kCFNull : RCTViewManagerModuleNameForClass(superClass), + @"Commands" : commands, }; }