Skip to content

Commit 8b0c333

Browse files
vonovakreact-native-bot
authored andcommitted
fix(ios): enable use of multiple RCTAppDependencyProvider instances (#49889)
Summary: instantiating multiple `RCTAppDependencyProvider` instances creates problems with their internal state, because the internal fields such as [`_thirdPartyFabricComponents` are populated once](https://github.com/facebook/react-native/blob/f5feb73022f9340583ebcf576eaedd3ca5677e1a/packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template#L60) for the entire app (see [`dispatch_once`](https://developer.apple.com/documentation/dispatch/1447169-dispatch_once)). That means when you create 2 instances, and call `thirdPartyFabricComponents` on them, the first instance will respond with a dictionary and the second with `nil`. This is unexpected. ## Changelog: [IOS] [FIXED] - enable use of multiple `RCTAppDependencyProvider` instances Pull Request resolved: #49889 Test Plan: `rnTester` - the templates are used by codegen. Running `pod install`, the files were generated correctly from the `.template` files. I was able to verify that accessing `thirdPartyFabricComponents` on multiple instances of `RCTAppDependencyProvider` returns valid result. <details> <summary>screenshot</summary> <img width="789" alt="Screenshot 2025-03-07 at 15 11 22" src="https://github.com/user-attachments/assets/9270ba90-ae7f-491a-a53a-f7e1f4606438" /> </details> Reviewed By: javache Differential Revision: D70892779 Pulled By: cipolleschi fbshipit-source-id: 27c7c8fd9982b6427daec02e0de59b08ad20bfad
1 parent b63040f commit 8b0c333

5 files changed

+78
-73
lines changed

Diff for: packages/react-native/scripts/codegen/generate-artifacts-executor.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ function generateCustomURLHandlers(libraries, outputDir) {
613613
)
614614
.filter(Boolean)
615615
.map(className => `@"${className}"`)
616-
.join(',\n\t\t');
616+
.join(',\n\t\t\t');
617617

618618
const customImageDataDecoderClasses = libraries
619619
.flatMap(
@@ -622,7 +622,7 @@ function generateCustomURLHandlers(libraries, outputDir) {
622622
)
623623
.filter(Boolean)
624624
.map(className => `@"${className}"`)
625-
.join(',\n\t\t');
625+
.join(',\n\t\t\t');
626626

627627
const customURLHandlerClasses = libraries
628628
.flatMap(
@@ -631,7 +631,7 @@ function generateCustomURLHandlers(libraries, outputDir) {
631631
)
632632
.filter(Boolean)
633633
.map(className => `@"${className}"`)
634-
.join(',\n\t\t');
634+
.join(',\n\t\t\t');
635635

636636
const template = fs.readFileSync(MODULES_PROTOCOLS_MM_TEMPLATE_PATH, 'utf8');
637637
const finalMMFile = template
@@ -736,7 +736,7 @@ function generateRCTModuleProviders(
736736
.flatMap(library => {
737737
const modules = modulesInLibraries[library];
738738
return modules.map(({moduleName, className}) => {
739-
return `\t\t@"${moduleName}": @"${className}", // ${library}`;
739+
return `\t\t\t@"${moduleName}": @"${className}", // ${library}`;
740740
});
741741
})
742742
.join('\n');
@@ -805,7 +805,7 @@ function generateRCTThirdPartyComponents(libraries, outputDir) {
805805
.flatMap(library => {
806806
const components = componentsInLibraries[library];
807807
return components.map(({componentName, className}) => {
808-
return `\t\t@"${componentName}": NSClassFromString(@"${className}"), // ${library}`;
808+
return `\t\t\t@"${componentName}": NSClassFromString(@"${className}"), // ${library}`;
809809
});
810810
})
811811
.join('\n');

Diff for: packages/react-native/scripts/codegen/templates/RCTAppDependencyProviderMM.template

+6-36
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,26 @@
1010
#import <ReactCodegen/RCTThirdPartyComponentsProvider.h>
1111
#import <ReactCodegen/RCTModuleProviders.h>
1212

13-
@implementation RCTAppDependencyProvider {
14-
NSArray<NSString *> * _URLRequestHandlerClassNames;
15-
NSArray<NSString *> * _imageDataDecoderClassNames;
16-
NSArray<NSString *> * _imageURLLoaderClassNames;
17-
NSDictionary<NSString *,Class<RCTComponentViewProtocol>> * _thirdPartyFabricComponents;
18-
NSDictionary<NSString *, id<RCTModuleProvider>> * _moduleProviders;
19-
}
13+
@implementation RCTAppDependencyProvider
2014

2115
- (nonnull NSArray<NSString *> *)URLRequestHandlerClassNames {
22-
static dispatch_once_t requestUrlToken;
23-
dispatch_once(&requestUrlToken, ^{
24-
self->_URLRequestHandlerClassNames = RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames;
25-
});
26-
27-
return _URLRequestHandlerClassNames;
16+
return RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames;
2817
}
2918

3019
- (nonnull NSArray<NSString *> *)imageDataDecoderClassNames {
31-
static dispatch_once_t dataDecoderToken;
32-
dispatch_once(&dataDecoderToken, ^{
33-
_imageDataDecoderClassNames = RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames;
34-
});
35-
36-
return _imageDataDecoderClassNames;
20+
return RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames;
3721
}
3822

3923
- (nonnull NSArray<NSString *> *)imageURLLoaderClassNames {
40-
static dispatch_once_t urlLoaderToken;
41-
dispatch_once(&urlLoaderToken, ^{
42-
_imageURLLoaderClassNames = RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames;
43-
});
44-
45-
return _imageURLLoaderClassNames;
24+
return RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames;
4625
}
4726

4827
- (nonnull NSDictionary<NSString *,Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents {
49-
static dispatch_once_t nativeComponentsToken;
50-
dispatch_once(&nativeComponentsToken, ^{
51-
_thirdPartyFabricComponents = RCTThirdPartyComponentsProvider.thirdPartyFabricComponents;
52-
});
53-
54-
return _thirdPartyFabricComponents;
28+
return RCTThirdPartyComponentsProvider.thirdPartyFabricComponents;
5529
}
5630

5731
- (nonnull NSDictionary<NSString *, id<RCTModuleProvider>> *)moduleProviders {
58-
static dispatch_once_t modulesToken;
59-
dispatch_once(&modulesToken, ^{
60-
_moduleProviders = RCTModuleProviders.moduleProviders;
61-
});
62-
return _moduleProviders;
32+
return RCTModuleProviders.moduleProviders;
6333
}
6434

6535
@end

Diff for: packages/react-native/scripts/codegen/templates/RCTModuleProvidersMM.template

+28-21
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,37 @@
1515

1616
+ (NSDictionary<NSString *, id<RCTModuleProvider>> *)moduleProviders
1717
{
18-
NSDictionary<NSString *, NSString *> * moduleMapping = @{
19-
{moduleMapping}
20-
};
21-
22-
NSMutableDictionary *dict = [NSMutableDictionary new];
23-
24-
for (NSString *key in moduleMapping) {
25-
NSString * moduleProviderName = moduleMapping[key];
26-
Class klass = NSClassFromString(moduleProviderName);
27-
if (!klass) {
28-
RCTLogError(@"Module provider %@ cannot be found in the runtime", moduleProviderName);
29-
continue;
18+
static NSDictionary<NSString *, id<RCTModuleProvider>> *providers = nil;
19+
static dispatch_once_t onceToken;
20+
21+
dispatch_once(&onceToken, ^{
22+
NSDictionary<NSString *, NSString *> * moduleMapping = @{
23+
{moduleMapping}
24+
};
25+
26+
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:moduleMapping.count];
27+
28+
for (NSString *key in moduleMapping) {
29+
NSString * moduleProviderName = moduleMapping[key];
30+
Class klass = NSClassFromString(moduleProviderName);
31+
if (!klass) {
32+
RCTLogError(@"Module provider %@ cannot be found in the runtime", moduleProviderName);
33+
continue;
34+
}
35+
36+
id instance = [klass new];
37+
if (![instance respondsToSelector:@selector(getTurboModule:)]) {
38+
RCTLogError(@"Module provider %@ does not conform to RCTModuleProvider", moduleProviderName);
39+
continue;
40+
}
41+
42+
[dict setObject:instance forKey:key];
3043
}
3144

32-
id instance = [klass new];
33-
if (![instance respondsToSelector:@selector(getTurboModule:)]) {
34-
RCTLogError(@"Module provider %@ does not conform to RCTModuleProvider", moduleProviderName);
35-
continue;
36-
}
37-
38-
[dict setObject:instance forKey:key];
39-
}
45+
providers = dict;
46+
});
4047

41-
return dict;
48+
return providers;
4249
}
4350

4451
@end

Diff for: packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderMM.template

+30-9
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,44 @@
1111

1212
+(NSArray<NSString *> *)imageURLLoaderClassNames
1313
{
14-
return @[
15-
{imageURLLoaderClassNames}
16-
];
14+
static NSArray<NSString *> *classNames = nil;
15+
static dispatch_once_t onceToken;
16+
17+
dispatch_once(&onceToken, ^{
18+
classNames = @[
19+
{imageURLLoaderClassNames}
20+
];
21+
});
22+
23+
return classNames;
1724
}
1825

1926
+(NSArray<NSString *> *)imageDataDecoderClassNames
2027
{
21-
return @[
22-
{imageDataDecoderClassNames}
23-
];
28+
static NSArray<NSString *> *classNames = nil;
29+
static dispatch_once_t onceToken;
30+
31+
dispatch_once(&onceToken, ^{
32+
classNames = @[
33+
{imageDataDecoderClassNames}
34+
];
35+
});
36+
37+
return classNames;
2438
}
2539

2640
+(NSArray<NSString *> *)URLRequestHandlerClassNames
2741
{
28-
return @[
29-
{requestHandlersClassNames}
30-
];
42+
static NSArray<NSString *> *classNames = nil;
43+
static dispatch_once_t onceToken;
44+
45+
dispatch_once(&onceToken, ^{
46+
classNames = @[
47+
{requestHandlersClassNames}
48+
];
49+
});
50+
51+
return classNames;
3152
}
3253

3354
@end

Diff for: packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderMM.template

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515

1616
+ (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
1717
{
18-
return @{
18+
static NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *thirdPartyComponents = nil;
19+
static dispatch_once_t nativeComponentsToken;
20+
21+
dispatch_once(&nativeComponentsToken, ^{
22+
thirdPartyComponents = @{
1923
{thirdPartyComponentsMapping}
20-
};
24+
};
25+
});
26+
27+
return thirdPartyComponents;
2128
}
2229

2330
@end

0 commit comments

Comments
 (0)