From fe1057afcd98b7995a5401efa513bdb04f1f46b7 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Tue, 12 Nov 2024 07:38:03 -0800 Subject: [PATCH] Let lib maintainer be explicit with componentProvider mapping (#47520) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/47520 Right now, when a 3p library needs to register a component in the component system, we have to crawl the library to try and get the mappng, best effort. With this approach, we are enriching the `codegenConfig` property to allow library developers to define the mapping themselves. For example: ```json //... "codegenConfig": { //.. "ios": { "componentProvider": { "RNTMyNativeView": "RNTMyNativeViewComponentView" } } }, ``` means that the JS component `RNTMyNativeView` will be mapped to the `RNTMyNativeViewComponentView` class. This also work for local apps, and it warns the users about what libraries are using the deprecated approach, so they can open an issue or a PR to those libraries. ## Changelog: [iOS][Added] - Allow 3p developers to specify the association between components and classes in Fabric Reviewed By: dmytrorykun Differential Revision: D65666061 fbshipit-source-id: 692e753635873ff9260e131d2d18ed226b2378c2 --- packages/helloworld/Gemfile.lock | 1 + .../ios/HelloWorld.xcodeproj/project.pbxproj | 89 ++++++++++++++++--- .../react-native-test-library/package.json | 5 ++ .../codegen/generate-artifacts-executor.js | 23 ++++- packages/rn-tester/package.json | 5 ++ 5 files changed, 112 insertions(+), 11 deletions(-) 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/scripts/codegen/generate-artifacts-executor.js b/packages/react-native/scripts/codegen/generate-artifacts-executor.js index bd2f24b5c41559..3e79c45ad685c2 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor.js @@ -646,16 +646,37 @@ function generateRCTThirdPartyComponents(libraries, outputDir) { 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'); - componentsInLibraries[libraryName] = files + 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) 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": {