Skip to content

Commit 04ea976

Browse files
fkgozalifacebook-github-bot
authored andcommitted
iOS: register lazy nativemodules on startup when Chrome is attached
Summary: @public This allows apps to specify custom lazy modules that they need to load during chrome debugging. This is because lazy modules won't be available on start up, hence these modules will be missing in JS land, causing problems. Reviewed By: shergin Differential Revision: D12899408 fbshipit-source-id: dca313648e994b22e3ee5afec856ef76470065f9
1 parent 5431607 commit 04ea976

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

React/Base/RCTBridgeDelegate.h

+5
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,9 @@
7272
- (void)loadSourceForBridge:(RCTBridge *)bridge
7373
withBlock:(RCTSourceLoadBlock)loadCallback;
7474

75+
/**
76+
* Retrieve the list of lazy-native-modules names for the given bridge.
77+
*/
78+
- (NSDictionary<NSString *, Class> *)extraLazyModuleClassesForBridge:(RCTBridge *)bridge;
79+
7580
@end

React/CxxBridge/RCTCxxBridge.mm

+52
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ - (void)start
301301
[self registerExtraModules];
302302
// Initialize all native modules that cannot be loaded lazily
303303
(void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
304+
[self registerExtraLazyModules];
304305

305306
[_performanceLogger markStopForTag:RCTPLNativeModuleInit];
306307

@@ -600,6 +601,57 @@ - (void)registerExtraModules
600601
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
601602
}
602603

604+
- (void)registerExtraLazyModules
605+
{
606+
#if RCT_DEBUG
607+
// This is debug-only and only when Chrome is attached, since it expects all modules to be already
608+
// available on start up. Otherwise, we can let the lazy module discovery to load them on demand.
609+
Class executorClass = [_parentBridge executorClass];
610+
if (executorClass && [NSStringFromClass(executorClass) isEqualToString:@"RCTWebSocketExecutor"]) {
611+
NSDictionary<NSString *, Class> *moduleClasses = nil;
612+
if ([self.delegate respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) {
613+
moduleClasses = [self.delegate extraLazyModuleClassesForBridge:_parentBridge];
614+
}
615+
616+
if (!moduleClasses) {
617+
return;
618+
}
619+
620+
// This logic is mostly copied from `registerModulesForClasses:`, but with one difference:
621+
// we must use the names provided by the delegate method here.
622+
for (NSString *moduleName in moduleClasses) {
623+
Class moduleClass = moduleClasses[moduleName];
624+
if (RCTJSINativeModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTJSINativeModule)]) {
625+
continue;
626+
}
627+
628+
// Check for module name collisions
629+
RCTModuleData *moduleData = _moduleDataByName[moduleName];
630+
if (moduleData) {
631+
if (moduleData.hasInstance) {
632+
// Existing module was preregistered, so it takes precedence
633+
continue;
634+
} else if ([moduleClass new] == nil) {
635+
// The new module returned nil from init, so use the old module
636+
continue;
637+
} else if ([moduleData.moduleClass new] != nil) {
638+
// Both modules were non-nil, so it's unclear which should take precedence
639+
RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the "
640+
"name '%@', but name was already registered by class %@",
641+
moduleClass, moduleName, moduleData.moduleClass);
642+
}
643+
}
644+
645+
moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
646+
647+
_moduleDataByName[moduleName] = moduleData;
648+
[_moduleClassesByID addObject:moduleClass];
649+
[_moduleDataByID addObject:moduleData];
650+
}
651+
}
652+
#endif
653+
}
654+
603655
- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules
604656
withDispatchGroup:(dispatch_group_t)dispatchGroup
605657
lazilyDiscovered:(BOOL)lazilyDiscovered

0 commit comments

Comments
 (0)