[RN][iOS]Add basic support for TM in Swift - Codegen Disabled

This commit is contained in:
Riccardo Cipolleschi
2025-07-18 16:15:14 +01:00
parent 5cda3065ce
commit c3c0c7cd15
7 changed files with 71 additions and 24 deletions
@@ -0,0 +1,11 @@
//
// RCTModule.mm
// Pods
//
// Created by Riccardo Cipolleschi on 18/07/2025.
//
@protocol RCTModule
@end
@@ -0,0 +1,13 @@
//
// RCTSwiftTurboModule.h
// Pods
//
// Created by Riccardo Cipolleschi on 18/07/2025.
//
#import "RCTModule.h"
@protocol RCTSwiftTurboModule <RCTModule>
@end
@@ -19,8 +19,10 @@
#import <string>
#import <unordered_map>
#import "RCTModule.h"
#define RCT_IS_TURBO_MODULE_CLASS(klass) \
((RCTTurboModuleEnabled() && [(klass) conformsToProtocol:@protocol(RCTTurboModule)]))
((RCTTurboModuleEnabled() && [(klass) conformsToProtocol:@protocol(RCTModule)]))
#define RCT_IS_TURBO_MODULE_INSTANCE(module) RCT_IS_TURBO_MODULE_CLASS([(module) class])
namespace facebook::react {
@@ -186,13 +188,20 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
*/
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params;
@optional
/**
* Return an instance of an Apple Module
*/
- (Class<RCTModule>)getAppleModule;
@end
/**
* Protocol that objects can inherit to conform to be treated as turbomodules.
* It inherits from RCTTurboModuleProvider, meaning that a TurboModule can create itself
*/
@protocol RCTTurboModule <RCTModuleProvider>
@protocol RCTTurboModule <RCTModule, RCTModuleProvider>
@optional
- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper;
@@ -210,3 +219,4 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
- (std::shared_ptr<facebook::react::NativeMethodCallInvoker>)decorateNativeMethodCallInvoker:
(std::shared_ptr<facebook::react::NativeMethodCallInvoker>)nativeMethodCallInvoker;
@end
@@ -847,7 +847,7 @@ void ObjCTurboModule::setMethodArgConversionSelector(NSString *methodName, size_
void ObjCTurboModule::setEventEmitterCallback(EventEmitterCallback eventEmitterCallback)
{
if ([instance_ conformsToProtocol:@protocol(RCTTurboModule)] &&
if ([instance_ conformsToProtocol:@protocol(RCTModule)] &&
[instance_ respondsToSelector:@selector(setEventEmitterCallback:)]) {
EventEmitterCallbackWrapper *wrapper = [EventEmitterCallbackWrapper new];
wrapper->_eventEmitterCallback = std::move(eventEmitterCallback);
@@ -859,3 +859,4 @@ void ObjCTurboModule::setEventEmitterCallback(EventEmitterCallback eventEmitterC
@implementation EventEmitterCallbackWrapper
@end
@@ -159,7 +159,7 @@ class LegacyModuleNativeMethodCallInvoker : public ModuleNativeMethodCallInvoker
bool isTurboModuleClass(Class cls)
{
return [cls conformsToProtocol:@protocol(RCTTurboModule)];
return [cls conformsToProtocol:@protocol(RCTModule)];
}
bool isTurboModuleInstance(id module)
@@ -339,18 +339,24 @@ typedef struct {
/**
* Step 2: Look for platform-specific modules.
*/
id<RCTModuleProvider> module = [self _moduleProviderForName:moduleName];
id<RCTModuleProvider> moduleProvider = [self _moduleProviderForName:moduleName];
TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);
// If we request that a TurboModule be created, its respective ObjC class must exist
// If the class doesn't exist, then _provideObjCModule returns nil
if (!module) {
if (!moduleProvider) {
return nullptr;
}
id<RCTModuleProvider> module = nullptr;
if ([moduleProvider respondsToSelector:@selector(getAppleModule)]) {
module = (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:moduleProvider];
}
id<RCTModuleProvider> moduleOrProvider = module ? module : moduleProvider;
std::shared_ptr<NativeMethodCallInvoker> nativeMethodCallInvoker = nullptr;
dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(module, &kAssociatedMethodQueueKey);
dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(moduleOrProvider, &kAssociatedMethodQueueKey);
if (methodQueue) {
/**
* Step 2c: Create and native CallInvoker from the TurboModule's method queue.
@@ -370,11 +376,11 @@ typedef struct {
* Step 2d: If the moduleClass is a legacy CxxModule, return a TurboCxxModule instance that
* wraps CxxModule.
*/
Class moduleClass = [module class];
Class moduleClass = [moduleOrProvider class];
if ([moduleClass isSubclassOfClass:RCTCxxModule.class]) {
// Use TurboCxxModule compat class to wrap the CxxModule instance.
// This is only for migration convenience, despite less performant.
auto turboModule = std::make_shared<TurboCxxModule>([((RCTCxxModule *)module) createModule], _jsInvoker);
auto turboModule = std::make_shared<TurboCxxModule>([((RCTCxxModule *)moduleOrProvider) createModule], _jsInvoker);
_turboModuleCache.insert({moduleName, turboModule});
return turboModule;
}
@@ -385,27 +391,27 @@ typedef struct {
* Use respondsToSelector: below to infer conformance to @protocol(RCTTurboModule). Using conformsToProtocol: is
* expensive.
*/
if ([module respondsToSelector:@selector(getTurboModule:)]) {
if ([moduleProvider respondsToSelector:@selector(getTurboModule:)]) {
ObjCTurboModule::InitParams params = {
.moduleName = moduleName,
.instance = (id<RCTBridgeModule>)module,
.instance = (id<RCTBridgeModule>)moduleOrProvider,
.jsInvoker = _jsInvoker,
.nativeMethodCallInvoker = nativeMethodCallInvoker,
.isSyncModule = methodQueue == RCTJSThread,
.shouldVoidMethodsExecuteSync = (bool)RCTTurboModuleSyncVoidMethodsEnabled(),
};
auto turboModule = [(id<RCTTurboModule>)module getTurboModule:params];
auto turboModule = [(id<RCTTurboModule>)moduleProvider getTurboModule:params];
if (turboModule == nullptr) {
RCTLogError(@"TurboModule \"%@\"'s getTurboModule: method returned nil.", moduleClass);
}
_turboModuleCache.insert({moduleName, turboModule});
if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:callInvoker:)]) {
[(id<RCTTurboModuleWithJSIBindings>)module installJSIBindingsWithRuntime:*runtime callInvoker:_jsInvoker];
} else if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:)]) {
if ([moduleOrProvider respondsToSelector:@selector(installJSIBindingsWithRuntime:callInvoker:)]) {
[(id<RCTTurboModuleWithJSIBindings>)moduleOrProvider installJSIBindingsWithRuntime:*runtime callInvoker:_jsInvoker];
} else if ([moduleOrProvider respondsToSelector:@selector(installJSIBindingsWithRuntime:)]) {
// Old API without CallInvoker (deprecated)
[(id<RCTTurboModuleWithJSIBindings>)module installJSIBindingsWithRuntime:*runtime];
[(id<RCTTurboModuleWithJSIBindings>)moduleOrProvider installJSIBindingsWithRuntime:*runtime];
}
return turboModule;
}
@@ -496,16 +502,16 @@ typedef struct {
if ([_delegate respondsToSelector:@selector(getModuleProvider:)]) {
moduleProvider = [_delegate getModuleProvider:moduleName];
}
if (RCTTurboModuleInteropEnabled() && ![self _isTurboModule:moduleName] && !moduleProvider) {
return nil;
}
if (moduleProvider) {
if ([moduleProvider conformsToProtocol:@protocol(RCTTurboModule)]) {
// moduleProvider is also a TM, we need to initialize objectiveC properties, like the dispatch queue
if ([moduleProvider conformsToProtocol:@protocol(RCTModule)]) {
return (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:moduleProvider];
}
// module is Cxx module
return moduleProvider;
}
@@ -585,7 +591,12 @@ typedef struct {
/**
* Step 2a: Resolve platform-specific class.
*/
Class moduleClass = moduleProvider ? [moduleProvider class] : [self _getModuleClassFromName:moduleName];
Class moduleClass = moduleProvider ?
([moduleProvider respondsToSelector:@selector(getAppleModule)] ?
[moduleProvider getAppleModule] :
[moduleProvider class]) :
[self _getModuleClassFromName:moduleName];
__block id<RCTBridgeModule> module = nil;
@@ -640,7 +651,7 @@ typedef struct {
return [moduleClass conformsToProtocol:@protocol(RCTBridgeModule)];
}
return [moduleClass conformsToProtocol:@protocol(RCTTurboModule)];
return [moduleClass conformsToProtocol:@protocol(RCTModule)];
}
/**
@@ -1104,3 +1115,4 @@ typedef struct {
}
@end
@@ -22,7 +22,7 @@ Pod::Spec.new do |s|
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = "**/RCTAppDependencyProvider.{h,mm}"
s.source_files = ["**/RCTAppDependencyProvider.{h,mm}", "**/*-Swift.{h,mm}"]
# This guard prevent to install the dependencies when we run `pod install` in the old architecture.
s.pod_target_xcconfig = {
+1 -1
View File
@@ -23,7 +23,7 @@ program
android: {},
},
root: path.join(__dirname, '../'),
reactNativePath: path.join(__dirname, '../../react-native'),
reactNativePath: path.join(__dirname, '../../../packages/react-native'),
},
{
experimentalDebugger: false,