Skip to content

Commit 0ceefb4

Browse files
RSNarafacebook-github-bot
authored andcommitted
Enable module lookup in TurboModules
Summary: NativeModules are instantiated by the bridge. If they choose, they can capture the bridge instance that instantiated them. From within the NativeModule, the bridge can then be used to lookup other NativeModules. TurboModules have no way to do such a lookup. Both NativeModules and TurboModules need to be able to query for one another. Therefore, we have four cases: 1. NativeModule accesses NativeModule. 2. NativeModule accesses TurboModule. 3. TurboModule accesses NativeModule. 4. TurboModule accesses TurboModule. In summary, this solution extends the bridge to support querying TurboModules. It also introduces a `RCTTurboModuleLookupDelegate` protocol, which, implemented by `RCTTurboModuleManager`, supports querying TurboModules: ``` protocol RCTTurboModuleLookupDelegate <NSObject> - (id)moduleForName:(NSString *)moduleName; - (id)moduleForName:(NSString *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure; - (BOOL)moduleIsInitialized:(NSString *)moduleName end ``` If TurboModules want to query other TurboModules, then they need to implement this protocol and synthesize `turboModuleLookupDelegate`: ``` protocol RCTTurboModuleWithLookupCapabilities property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate; end ``` NativeModules will continue to use `RCTBridge` to access other NativeModules. Nothing needs to change. When we attach the bridge to `RCTTurboModuleManager`, we also attach `RCTTurboModuleManager` to the bridge as a `RCTTurboModuleLookupDelegate`. This allows the bridge to query TurboModules, which enables our NativeModules to transparently (i.e: without any NativeModule code modification) query TurboModules. In an ideal world, all modules would be TurboModules. Until then, we're going to require that TurboModules use the bridge to query for NativeModules or TurboModules. `RCTTurboModuleManager` keeps a map of all TurboModules that we instantiated. We simply search in this map and return the TurboModule. This setup allows us to switch NativeModules to TurboModules without compromising their ability to use the bridge to search for other NativeModules (and TurboModules). When we write new TurboModules, we can have them use `RCTTurboModuleLookupDelegate` to do access other TurboModules. Eventually, after we migrate all NativeModules to TurboModules, we can migrate all old callsites to use `RCTTurboModuleLookupDelegate`. Reviewed By: fkgozali Differential Revision: D13553186 fbshipit-source-id: 4d0488eef081332c8b70782e1337eccf10717dae
1 parent dfcbf97 commit 0ceefb4

7 files changed

Lines changed: 260 additions & 73 deletions

File tree

React/Base/RCTBridge.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ RCT_EXTERN void RCTEnableTurboModule(BOOL enabled);
159159
// Note: This method lazily load the module as necessary.
160160
- (id)moduleForClass:(Class)moduleClass;
161161

162+
/**
163+
* When a NativeModule performs a lookup for a TurboModule, we need to query
164+
* the lookupDelegate.
165+
*/
166+
- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate;
167+
162168
/**
163169
* Convenience method for retrieving all modules conforming to a given protocol.
164170
* Modules will be sychronously instantiated if they haven't already been,

React/Base/RCTBridge.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ - (void)dealloc
226226
[self invalidate];
227227
}
228228

229+
- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
230+
{
231+
[self.batchedBridge setRCTTurboModuleLookupDelegate:turboModuleLookupDelegate];
232+
}
233+
229234
- (void)didReceiveReloadCommand
230235
{
231236
[self reload];

React/Base/RCTBridgeModule.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,26 @@ RCT_EXTERN void RCTRegisterModule(Class); \
322322

323323
@end
324324

325+
/**
326+
* A protocol that allows TurboModules to do lookup on other TurboModules.
327+
* Calling these methods may cause a module to be synchronously instantiated.
328+
*/
329+
@protocol RCTTurboModuleLookupDelegate <NSObject>
330+
- (id)moduleForName:(const char *)moduleName;
331+
332+
/**
333+
* Rationale:
334+
* When TurboModules lookup other modules by name, we first check the TurboModule
335+
* registry to see if a TurboModule exists with the respective name. In this case,
336+
* we don't want a RedBox to be raised if the TurboModule isn't found.
337+
*
338+
* This method is deprecated and will be deleted after the migration from
339+
* TurboModules to TurboModules is complete.
340+
*/
341+
- (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure;
342+
- (BOOL)moduleIsInitialized:(const char *)moduleName;
343+
@end
344+
325345
/**
326346
* Experimental.
327347
* A protocol to declare that a class supports TurboModule.

React/CxxBridge/RCTCxxBridge.mm

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,21 @@ @implementation RCTCxxBridge
172172

173173
// This is uniquely owned, but weak_ptr is used.
174174
std::shared_ptr<Instance> _reactInstance;
175+
176+
// Necessary for searching in TurboModuleRegistry
177+
id<RCTTurboModuleLookupDelegate> _turboModuleLookupDelegate;
175178
}
176179

177180
@synthesize bridgeDescription = _bridgeDescription;
178181
@synthesize loading = _loading;
179182
@synthesize performanceLogger = _performanceLogger;
180183
@synthesize valid = _valid;
181184

185+
- (void) setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
186+
{
187+
_turboModuleLookupDelegate = turboModuleLookupDelegate;
188+
}
189+
182190
- (std::shared_ptr<MessageQueueThread>)jsMessageThread
183191
{
184192
return _jsMessageThread;
@@ -428,13 +436,23 @@ - (RCTModuleData *)moduleDataForName:(NSString *)moduleName
428436

429437
- (id)moduleForName:(NSString *)moduleName
430438
{
431-
return _moduleDataByName[moduleName].instance;
439+
return [self moduleForName:moduleName lazilyLoadIfNecessary:NO];
432440
}
433441

434442
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
435443
{
444+
if (RCTTurboModuleEnabled() && _turboModuleLookupDelegate) {
445+
const char* moduleNameCStr = [moduleName UTF8String];
446+
if (lazilyLoad || [_turboModuleLookupDelegate moduleIsInitialized:moduleNameCStr]) {
447+
id<RCTTurboModule> module = [_turboModuleLookupDelegate moduleForName:moduleNameCStr warnOnLookupFailure:NO];
448+
if (module != nil) {
449+
return module;
450+
}
451+
}
452+
}
453+
436454
if (!lazilyLoad) {
437-
return [self moduleForName:moduleName];
455+
return _moduleDataByName[moduleName].instance;
438456
}
439457

440458
RCTModuleData *moduleData = _moduleDataByName[moduleName];
@@ -463,7 +481,16 @@ - (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoa
463481

464482
- (BOOL)moduleIsInitialized:(Class)moduleClass
465483
{
466-
return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
484+
NSString* moduleName = RCTBridgeModuleNameForClass(moduleClass);
485+
if (_moduleDataByName[moduleName].hasInstance) {
486+
return YES;
487+
}
488+
489+
if (_turboModuleLookupDelegate) {
490+
return [_turboModuleLookupDelegate moduleIsInitialized:[moduleName UTF8String]];
491+
}
492+
493+
return NO;
467494
}
468495

469496
- (id)moduleForClass:(Class)moduleClass

ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,17 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
3939
} // namespace facebook
4040

4141
@protocol RCTTurboModule <NSObject>
42-
4342
@optional
43+
/**
44+
* Used by TurboModules to get access to other TurboModules.
45+
*
46+
* Usage:
47+
* Place `@synthesize turboModuleLookupDelegate = _turboModuleLookupDelegate`
48+
* in the @implementation section of your TurboModule.
49+
*/
50+
@property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate;
4451

52+
@optional
4553
// This should be required, after migration is done.
4654
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::JSCallInvoker>)jsInvoker;
4755

ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
@end
3636

37-
@interface RCTTurboModuleManager : NSObject
37+
@interface RCTTurboModuleManager : NSObject<RCTTurboModuleLookupDelegate>
3838

3939
- (instancetype)initWithRuntime:(facebook::jsi::Runtime *)runtime
4040
bridge:(RCTBridge *)bridge

0 commit comments

Comments
 (0)