diff --git a/packages/helloworld/Gemfile.lock b/packages/helloworld/Gemfile.lock index 69dee809db21a7..6f827425c2c396 100644 --- a/packages/helloworld/Gemfile.lock +++ b/packages/helloworld/Gemfile.lock @@ -97,6 +97,7 @@ PLATFORMS DEPENDENCIES activesupport (>= 6.1.7.5, < 7.1.0) cocoapods (~> 1.13, != 1.15.1, != 1.15.0) + xcodeproj (< 1.26.0) RUBY VERSION ruby 3.3.0p0 diff --git a/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj b/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj index 67b9cac0854b5b..edd07155bb12fb 100644 --- a/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj +++ b/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj @@ -8,13 +8,13 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; }; - 0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */; }; 6EA01F72FAC10D00AECACF94 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */; }; - 7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,13 +39,13 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HelloWorld/main.m; sourceTree = ""; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = HelloWorld/PrivacyInfo.xcprivacy; sourceTree = ""; }; - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B4392A12AC88292D35C810B /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = ""; }; 5709B34CF0A7D63546082F79 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = ""; }; 5B7EB9410499542E8C5724F5 /* Pods-HelloWorld-HelloWorldTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; sourceTree = ""; }; - 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = HelloWorld/LaunchScreen.storyboard; sourceTree = ""; }; + 82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 89C6BE57DB24E9ADA2F236DE /* Pods-HelloWorld-HelloWorldTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.release.xcconfig"; sourceTree = ""; }; + CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -54,7 +54,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */, + 68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,7 +62,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */, + D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -105,8 +105,8 @@ isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */, - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */, + 82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */, + CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */, ); name = Frameworks; sourceTree = ""; @@ -165,6 +165,7 @@ 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -186,6 +187,7 @@ 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -270,6 +272,23 @@ shellPath = /bin/sh; shellScript = "set -e\n\nexport CONFIG_JSON=$(sed -e \"s|HELLOWORLD_PATH|$(realpath \"${SRCROOT}/../\")|g\" \"${SRCROOT}/../.react-native.config\")\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; + A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -314,6 +333,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -535,6 +571,17 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + ); IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, @@ -555,8 +602,14 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; + USE_HERMES = true; }; name = Debug; }; @@ -602,6 +655,17 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", + "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + ); IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, @@ -621,8 +685,13 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; SDKROOT = iphoneos; + USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/packages/react-native-test-library/package.json b/packages/react-native-test-library/package.json index 054eb559809e88..c378871432ff36 100644 --- a/packages/react-native-test-library/package.json +++ b/packages/react-native-test-library/package.json @@ -44,6 +44,11 @@ "includesGeneratedCode": true, "android": { "javaPackageName": "com.reactnative.osslibraryexample" + }, + "ios": { + "componentProvider": { + "SampleNativeComponent": "RCTSampleNativeComponentComponentView" + } } } } diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm index 8a020c142a36d4..1d6e0e31eea336 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm @@ -34,6 +34,14 @@ #endif #import +#if __has_include() +#define USE_OSS_CODEGEN 1 +#import +#else +// Meta internal system do not generate the RCTModulesConformingToProtocolsProvider.h file +#define USE_OSS_CODEGEN 0 +#endif + using namespace facebook::react; @interface RCTAppDelegate () @@ -235,7 +243,11 @@ - (Class)getModuleClassFromName:(const char *)name - (NSDictionary> *)thirdPartyFabricComponents { +#if USE_OSS_CODEGEN + return [RCTThirdPartyComponentsProvider thirdPartyFabricComponents]; +#else return @{}; +#endif } - (RCTRootViewFactory *)createRCTRootViewFactory diff --git a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec index edaf73d1f060a1..729a7a0bb6a0d0 100644 --- a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec +++ b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec @@ -76,6 +76,7 @@ Pod::Spec.new do |s| s.dependency "React-nativeconfig" s.dependency "React-RCTFBReactNativeSpec" s.dependency "React-defaultsnativemodule" + s.dependency "ReactCodegen" add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"]) add_dependency(s, "React-NativeModulesApple") diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h index 54936a93de7c5c..027b8d2f696412 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h @@ -17,7 +17,6 @@ // OSS-compatibility layer #import -#import #import #pragma GCC diagnostic push diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm index f07b0301cd28a5..82fff92ff64b7e 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm @@ -38,7 +38,7 @@ auto classFunc = p->second; return classFunc(); } - return RCTThirdPartyFabricComponentsProvider(name); + return nullptr; } #endif // RN_DISABLE_OSS_PLUGIN_HEADER diff --git a/packages/react-native/scripts/cocoapods/codegen_utils.rb b/packages/react-native/scripts/cocoapods/codegen_utils.rb index 3c2aca4f0581d1..067184cd61dd43 100644 --- a/packages/react-native/scripts/cocoapods/codegen_utils.rb +++ b/packages/react-native/scripts/cocoapods/codegen_utils.rb @@ -121,7 +121,8 @@ def get_react_codegen_spec(package_json_file, folly_version: get_folly_config()[ 'source_files' => "**/*.{h,mm,cpp}", 'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" => header_search_paths.join(' '), - "FRAMEWORK_SEARCH_PATHS" => framework_search_paths + "FRAMEWORK_SEARCH_PATHS" => framework_search_paths, + "OTHER_CPLUSPLUSFLAGS" => "$(inherited) #{folly_compiler_flags} #{boost_compiler_flags}", }, 'dependencies': { "React-jsiexecutor": [], diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor.js b/packages/react-native/scripts/codegen/generate-artifacts-executor.js index b76d2d4e6153bb..3e79c45ad685c2 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor.js @@ -86,6 +86,22 @@ const MODULES_PROTOCOLS_MM_TEMPLATE_PATH = path.join( 'RCTModulesConformingToProtocolsProviderMM.template', ); +const THIRD_PARTY_COMPONENTS_H_TEMPLATE_PATH = path.join( + REACT_NATIVE_PACKAGE_ROOT_FOLDER, + 'scripts', + 'codegen', + 'templates', + 'RCTThirdPartyComponentsProviderH.template', +); + +const THIRD_PARTY_COMPONENTS_MM_TEMPLATE_PATH = path.join( + REACT_NATIVE_PACKAGE_ROOT_FOLDER, + 'scripts', + 'codegen', + 'templates', + 'RCTThirdPartyComponentsProviderMM.template', +); + const codegenLog = (text, info = false) => { // ANSI escape codes for colors and formatting const reset = '\x1b[0m'; @@ -541,28 +557,6 @@ function generateNativeCode( }); } -function rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform) { - return !pkgJsonIncludesGeneratedCode(pkgJson) && platform === 'ios'; -} - -function dependencyNeedsThirdPartyComponentProvider( - schemaInfo, - platform, - appCodegenConfigSpec, -) { - // Filter the react native core library out. - // In the future, core library and third party library should - // use the same way to generate/register the fabric components. - // We also have to filter out the the components defined in the app - // because the RCTThirdPartyComponentProvider is generated inside Fabric, - // which lives in a different target from the app and it has no visibility over - // the symbols defined in the app. - return ( - !isReactNativeCoreLibrary(schemaInfo.library.config.name, platform) && - schemaInfo.library.config.name !== appCodegenConfigSpec - ); -} - function mustGenerateNativeCode(includeLibraryPath, schemaInfo) { // If library's 'codegenConfig' sets 'includesGeneratedCode' to 'true', // then we assume that native code is shipped with the library, @@ -573,27 +567,6 @@ function mustGenerateNativeCode(includeLibraryPath, schemaInfo) { ); } -function createComponentProvider(schemas, supportedApplePlatforms) { - codegenLog('Creating component provider.', true); - const outputDir = path.join( - REACT_NATIVE_PACKAGE_ROOT_FOLDER, - 'React', - 'Fabric', - ); - fs.mkdirSync(outputDir, {recursive: true}); - utils.getCodegen().generateFromSchemas( - { - schemas: schemas, - outputDirectory: outputDir, - supportedApplePlatforms, - }, - { - generators: ['providerIOS'], - }, - ); - codegenLog(`Generated provider in: ${outputDir}`); -} - function findCodegenEnabledLibraries(pkgJson, projectRoot) { const projectLibraries = findProjectRootLibraries(pkgJson, projectRoot); if (pkgJsonIncludesGeneratedCode(pkgJson)) { @@ -655,6 +628,132 @@ function generateCustomURLHandlers(libraries, outputDir) { ); } +function generateRCTThirdPartyComponents(libraries, outputDir) { + fs.mkdirSync(outputDir, {recursive: true}); + // Generate Header File + codegenLog('Generating RCTThirdPartyComponentsProvider.h'); + const templateH = fs.readFileSync( + THIRD_PARTY_COMPONENTS_H_TEMPLATE_PATH, + 'utf8', + ); + const finalPathH = path.join(outputDir, 'RCTThirdPartyComponentsProvider.h'); + fs.writeFileSync(finalPathH, templateH); + codegenLog(`Generated artifact: ${finalPathH}`); + + codegenLog('Generating RCTThirdPartyComponentsProvider.mm'); + let componentsInLibraries = {}; + libraries.forEach(({config, libraryPath}) => { + if (isReactNativeCoreLibrary(config.name) || config.type === 'modules') { + return; + } + + const libraryName = JSON.parse( + fs.readFileSync(path.join(libraryPath, 'package.json')), + ).name; + if (config.ios?.componentProvider) { + componentsInLibraries[libraryName] = Object.keys( + config.ios?.componentProvider, + ).map(componentName => { + return { + componentName, + className: config.ios?.componentProvider[componentName], + }; + }); + return; + } + codegenLog(`Crawling ${libraryName} library for components`); + // crawl all files and subdirectories for file with the ".mm" extension + const files = findFilesWithExtension(libraryPath, '.mm'); + + const componentsMapping = files + .flatMap(file => findRCTComponentViewProtocolClass(file)) + .filter(Boolean); + + if (componentsMapping.length !== 0) { + codegenLog( + `[DEPRECATED] ${libraryName} should add the 'ios.componentProvider' property in their codegenConfig`, + true, + ); + } + + componentsInLibraries[libraryName] = componentsMapping; + }); + + const thirdPartyComponentsMapping = Object.keys(componentsInLibraries) + .flatMap(library => { + const components = componentsInLibraries[library]; + return components.map(({componentName, className}) => { + return `\t\t@"${componentName}": NSClassFromString(@"${className}"), // ${library}`; + }); + }) + .join('\n'); + // Generate implementation file + const templateMM = fs + .readFileSync(THIRD_PARTY_COMPONENTS_MM_TEMPLATE_PATH, 'utf8') + .replace(/{thirdPartyComponentsMapping}/, thirdPartyComponentsMapping); + const finalPathMM = path.join( + outputDir, + 'RCTThirdPartyComponentsProvider.mm', + ); + fs.writeFileSync(finalPathMM, templateMM); + codegenLog(`Generated artifact: ${finalPathMM}`); +} + +// Given a path, return the paths of all the files with extension .mm in +// the path dir and all its subdirectories. +function findFilesWithExtension(filePath, extension) { + const files = []; + const dir = fs.readdirSync(filePath); + dir.forEach(file => { + const absolutePath = path.join(filePath, file); + if ( + fs.existsSync(absolutePath) && + fs.statSync(absolutePath).isDirectory() + ) { + files.push(...findFilesWithExtension(absolutePath, extension)); + } else if (file.endsWith(extension)) { + files.push(absolutePath); + } + }); + return files; +} + +// Given a filepath, read the file and look for a string that starts with 'Class ' +// and ends with 'Cls(void)'. Return the string between the two. +function findRCTComponentViewProtocolClass(filepath) { + const fileContent = fs.readFileSync(filepath, 'utf8'); + const regex = /Class (.*)Cls\(/; + const match = fileContent.match(regex); + if (match) { + const componentName = match[1]; + + // split the file by \n + // remove all the lines before the one that matches the regex above + // find the first return statement after that that ends with .class + // return what's between return and `.class` + const lines = fileContent.split('\n'); + const signatureIndex = lines.findIndex(line => regex.test(line)); + const returnRegex = /return (.*)\.class/; + const classNameMatch = String(lines.slice(signatureIndex)).match( + returnRegex, + ); + if (classNameMatch) { + const className = classNameMatch[1]; + codegenLog(`Match found ${componentName} -> ${className}`); + return { + componentName, + className, + }; + } + + console.warn( + `Could not find class name for component ${componentName}. Register it manually`, + ); + return null; + } + return null; +} + // It removes all the empty files and empty folders // it finds, starting from `filepath`, recursively. // @@ -785,24 +884,8 @@ function execute(projectRoot, targetPlatform, baseOutputPath) { platform, ); - if ( - rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform) - ) { - const filteredSchemas = schemaInfos.filter(schemaInfo => - dependencyNeedsThirdPartyComponentProvider( - schemaInfo, - platform, - pkgJson.codegenConfig?.name, - ), - ); - const schemas = filteredSchemas.map(schemaInfo => schemaInfo.schema); - const supportedApplePlatforms = filteredSchemas.map( - schemaInfo => schemaInfo.supportedApplePlatforms, - ); - - createComponentProvider(schemas, supportedApplePlatforms); - generateCustomURLHandlers(libraries, outputPath); - } + generateRCTThirdPartyComponents(libraries, outputPath); + generateCustomURLHandlers(libraries, outputPath); cleanupEmptyFilesAndFolders(outputPath); } diff --git a/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderH.template b/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderH.template new file mode 100644 index 00000000000000..ab1a249de3580a --- /dev/null +++ b/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderH.template @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@protocol RCTComponentViewProtocol; + +@interface RCTThirdPartyComponentsProvider: NSObject + ++ (NSDictionary> *)thirdPartyFabricComponents; + +@end diff --git a/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderMM.template b/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderMM.template new file mode 100644 index 00000000000000..34f84bc5c6e4d2 --- /dev/null +++ b/packages/react-native/scripts/codegen/templates/RCTThirdPartyComponentsProviderMM.template @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +#import "RCTThirdPartyComponentsProvider.h" +#import + +@implementation RCTThirdPartyComponentsProvider + ++ (NSDictionary> *)thirdPartyFabricComponents +{ + return @{ +{thirdPartyComponentsMapping} + }; +} + +@end diff --git a/packages/rn-tester/RNTester/AppDelegate.mm b/packages/rn-tester/RNTester/AppDelegate.mm index eacc13101b2c61..cff5e645688c91 100644 --- a/packages/rn-tester/RNTester/AppDelegate.mm +++ b/packages/rn-tester/RNTester/AppDelegate.mm @@ -149,7 +149,14 @@ - (BOOL)bridgelessEnabled #ifndef RN_DISABLE_OSS_PLUGIN_HEADER - (nonnull NSDictionary> *)thirdPartyFabricComponents { - return @{@"RNTMyNativeView" : RNTMyNativeViewComponentView.class}; +#if USE_OSS_CODEGEN + return [super thirdPartyFabricComponents].mutableCopy; +#else + NSMutableDictionary *dict = [super thirdPartyFabricComponents].mutableCopy; + dict[@"RNTMyNativeView"] = NSClassFromString(@"RNTMyNativeViewComponentView"); + dict[@"SampleNativeComponent"] = NSClassFromString(@"RCTSampleNativeComponentComponentView"); + return dict; +#endif } #endif diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index 51ff079c14ab0e..48fa5f0de263b9 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -43,6 +43,11 @@ "jsSrcsDir": ".", "android": { "javaPackageName": "com.facebook.fbreact.specs" + }, + "ios": { + "componentProvider": { + "RNTMyNativeView": "RNTMyNativeViewComponentView" + } } }, "devDependencies": {