Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/react-native/React/Base/RCTBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ RCT_EXTERN_C_BEGIN
*/
NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);

/**
* This function returns the list of modules that have been registered using the Old Architecture mechanism.
*/
NSMutableArray<NSString *> *getModulesLoadedWithOldArch(void);

/**
* Experimental.
* Check/set if JSI-bound NativeModule is enabled. By default it's off.
Expand Down
94 changes: 94 additions & 0 deletions packages/react-native/React/Base/RCTBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,97 @@
return result;
}

NSSet<NSString *> *getCoreModuleClasses(void);
NSSet<NSString *> *getCoreModuleClasses(void)
{
static NSSet<NSString *> *coreModuleClasses = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coreModuleClasses = [NSSet setWithArray:@[
@"RCTViewManager",
@"RCTActivityIndicatorViewManager",
@"RCTDebuggingOverlayManager",
@"RCTModalHostViewManager",
@"RCTModalManager",
@"RCTRefreshControlManager",
@"RCTSafeAreaViewManager",
@"RCTScrollContentViewManager",
@"RCTScrollViewManager",
@"RCTSwitchManager",
@"RCTUIManager",
@"RCTAccessibilityManager",
@"RCTActionSheetManager",
@"RCTAlertManager",
@"RCTAppearance",
@"RCTAppState",
@"RCTClipboard",
@"RCTDeviceInfo",
@"RCTDevLoadingView",
@"RCTDevMenu",
@"RCTDevSettings",
@"RCTDevToolsRuntimeSettingsModule",
@"RCTEventDispatcher",
@"RCTExceptionsManager",
@"RCTI18nManager",
@"RCTKeyboardObserver",
@"RCTLogBox",
@"RCTPerfMonitor",
@"RCTPlatform",
@"RCTRedBox",
@"RCTSourceCode",
@"RCTStatusBarManager",
@"RCTTiming",
@"RCTWebSocketModule",
@"RCTNativeAnimatedModule",
@"RCTNativeAnimatedTurboModule",
@"RCTBlobManager",
@"RCTFileReaderModule",
@"RCTBundleAssetImageLoader",
@"RCTGIFImageDecoder",
@"RCTImageEditingManager",
@"RCTImageLoader",
@"RCTImageStoreManager",
@"RCTImageViewManager",
@"RCTLocalAssetImageLoader",
@"RCTLinkingManager",
@"RCTDataRequestHandler",
@"RCTFileRequestHandler",
@"RCTHTTPRequestHandler",
@"RCTNetworking",
@"RCTPushNotificationManager",
@"RCTSettingsManager",
@"RCTBaseTextViewManager",
@"RCTBaseTextInputViewManager",
@"RCTInputAccessoryViewManager",
@"RCTMultilineTextInputViewManager",
@"RCTRawTextViewManager",
@"RCTSinglelineTextInputViewManager",
@"RCTTextViewManager",
@"RCTVirtualTextViewManager",
@"RCTVibration",
]];
});

return coreModuleClasses;
}

static NSMutableArray<NSString *> *modulesLoadedWithOldArch;
void addModuleLoadedWithOldArch(NSString *);
void addModuleLoadedWithOldArch(NSString *moduleName)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
modulesLoadedWithOldArch = [NSMutableArray new];
});

[modulesLoadedWithOldArch addObject:moduleName];
}

NSMutableArray<NSString *> *getModulesLoadedWithOldArch(void)
{
return modulesLoadedWithOldArch;
}

/**
* Register the given class as a bridge module. All modules must be registered
* prior to the first bridge initialization.
Expand All @@ -50,6 +141,9 @@
void RCTRegisterModule(Class);
void RCTRegisterModule(Class moduleClass)
{
if (RCTIsNewArchEnabled() && ![getCoreModuleClasses() containsObject:[moduleClass description]]) {
addModuleLoadedWithOldArch([moduleClass description]);
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTModuleClasses = [NSMutableArray new];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,12 @@ class JSI_EXPORT ObjCInteropTurboModule : public ObjCTurboModule {
std::vector<MethodDescriptor> methodDescriptors_;
NSDictionary<NSString *, NSArray<NSString *> *> *methodArgumentTypeNames_;
jsi::Value constantsCache_;
std::unordered_set<std::string> warnedModuleInvocation_;

const jsi::Value &getConstants(jsi::Runtime &runtime);
bool exportsConstants();

void _logLegacyArchitectureWarning(NSString *moduleName, const std::string &methodName);
};

} // namespace react
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,15 @@ T RCTConvertTo(SEL selector, id json)
if (!this->constantsCache_.isUndefined()) {
return jsi::Value(rt, this->constantsCache_);
}
const std::string &methodName = this->methodDescriptors_[i].methodName;
NSString *moduleName = [[this->instance_ class] description];
this->_logLegacyArchitectureWarning(moduleName, methodName);

// TODO: Dispatch getConstants to the main queue, if the module requires main queue setup
jsi::Value ret = this->invokeObjCMethod(
rt,
this->methodDescriptors_[i].jsReturnKind,
this->methodDescriptors_[i].methodName,
methodName,
this->methodDescriptors_[i].selector,
args,
count);
Expand Down Expand Up @@ -305,10 +308,14 @@ T RCTConvertTo(SEL selector, id json)
propName,
static_cast<unsigned int>(methodDescriptors_[i].jsArgCount),
[this, i](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
const std::string &methodName = this->methodDescriptors_[i].methodName;
NSString *moduleName = [[this->instance_ class] description];
this->_logLegacyArchitectureWarning(moduleName, methodName);

return this->invokeObjCMethod(
rt,
this->methodDescriptors_[i].jsReturnKind,
this->methodDescriptors_[i].methodName,
methodName,
this->methodDescriptors_[i].selector,
args,
count);
Expand All @@ -327,6 +334,22 @@ T RCTConvertTo(SEL selector, id json)
return constant;
}

void ObjCInteropTurboModule::_logLegacyArchitectureWarning(NSString *moduleName, const std::string &methodName)
{
std::string separator = std::string(".");

std::string moduleInvocation = [moduleName cStringUsingEncoding:NSUTF8StringEncoding] + separator + methodName;
if (warnedModuleInvocation_.find(moduleInvocation) == warnedModuleInvocation_.end()) {
RCTLogWarn(
@"The `%@` module is invoking the `%s` method using the TurboModule interop layer. This is part of the compatibility layer with the Legacy Architecture. If `%@` is a local module, please migrate it to be a Native Module as described at https://reactnative.dev/docs/next/turbo-native-modules-introduction. If `%@` is a third party dependency, please open an issue in the library repository.",
moduleName,
methodName.c_str(),
moduleName,
moduleName);
warnedModuleInvocation_.insert(moduleInvocation);
}
}

void ObjCInteropTurboModule::setInvocationArg(
jsi::Runtime &runtime,
const char *methodNameCStr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,26 @@ - (void)_loadJSBundle:(NSURL *)sourceURL
// Set up hot module reloading in Dev only.
[strongSelf->_performanceLogger markStopForTag:RCTPLScriptDownload];
[devSettings setupHMRClientWithBundleURL:sourceURL];

[strongSelf _logOldArchitectureWarnings];
}];
}

- (void)_logOldArchitectureWarnings
{
NSMutableArray<NSString *> *modulesInOldArchMode = getModulesLoadedWithOldArch();
if (modulesInOldArchMode.count > 0) {
NSMutableString *moduleList = [NSMutableString new];
for (NSString *moduleName in modulesInOldArchMode) {
[moduleList appendFormat:@"- %@\n", moduleName];
}
RCTLogWarn(
@"The following modules have been registered using a RCT_EXPORT_MODULE. That's a Legacy Architecture API. Please migrate to the new approach as described in the https://reactnative.dev/docs/next/turbo-native-modules-introduction#register-the-native-module-in-your-app website or open a PR in the library repository:\n%@",
moduleList);
[modulesInOldArchMode removeAllObjects];
}
}

- (void)_loadScriptFromSource:(RCTSource *)source
{
std::lock_guard<std::mutex> lock(_invalidationMutex);
Expand Down