From eba1828a83ec8910f662cfeffe1a83589a4c404d Mon Sep 17 00:00:00 2001 From: Blake Friedman Date: Wed, 5 Jun 2024 09:08:16 -0700 Subject: [PATCH] directly call community-cli-plugin in react-native-xcode.sh (#44721) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44721 For iOS builds of `react-native`, the [react-native-xcode.sh](https://www.internalfb.com/code/fbsource/[7ad79aae3e8bf565d53f087ac7f7b7622b19acec]/xplat/js/react-native-github/packages/react-native/scripts/react-native-xcode.sh) script is executed as one of the build phases. This phase bundles the JS application (dev or production). I've updated this to use the new `bundle.js` script instead of calling the `react-native/cli.js`. This is identical except with how the config is captured: {F1669960016} This is similar to our approach with the Gradle plugin, giving Framework authors more control. **Other:** formatting changes for the Privacy Manifest that Xcode keeps updating. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D57915368 fbshipit-source-id: f52ea4b3cb94212ac97a3d7edeb68747418fe0a9 --- .eslintignore | 2 + packages/helloworld/.react-native.config | 22 ++++++ .../ios/HelloWorld.xcodeproj/project.pbxproj | 43 ++++-------- .../ios/HelloWorld/PrivacyInfo.xcprivacy | 63 ++++++++--------- packages/helloworld/ios/Podfile | 2 +- packages/react-native/package.json | 1 + packages/react-native/scripts/bundle.js | 70 +++++++++++++++++++ .../scripts/react-native-xcode.sh | 15 +++- 8 files changed, 151 insertions(+), 67 deletions(-) create mode 100644 packages/helloworld/.react-native.config create mode 100644 packages/react-native/scripts/bundle.js diff --git a/.eslintignore b/.eslintignore index e35c03e132f..da763c3a56b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,6 +2,8 @@ **/staticBundle.js docs/generatedComponentApiDocs.js packages/react-native/flow/ +packages/react-native/sdks/ +packages/react-native/ReactAndroid/hermes-engine/build/ packages/react-native/Libraries/Renderer/* packages/react-native/Libraries/vendor/**/* node_modules/ diff --git a/packages/helloworld/.react-native.config b/packages/helloworld/.react-native.config new file mode 100644 index 00000000000..77e3f14b0d8 --- /dev/null +++ b/packages/helloworld/.react-native.config @@ -0,0 +1,22 @@ +{ + "platforms": { + "ios": {}, + "android": {} + }, + "project": { + "ios": { + "sourceDir": "HELLOWORLD_PATH/ios", + "xcodeProject": { + "name": "HelloWorld.xcworkspace", + "isWorkspace": true + } + }, + "android": { + "sourceDir": "HELLOWORLD_PATH/android", + "appName": "app", + "packageName": "com.helloworld", + "applicationId": "com.helloworld", + "mainActivity": ".MainActivity" + } + } +} diff --git a/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj b/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj index c727b930811..5bbbcca7dc9 100644 --- a/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj +++ b/packages/helloworld/ios/HelloWorld.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 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 */; }; + 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 */; }; /* End PBXBuildFile section */ @@ -30,6 +31,7 @@ 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* HelloWorldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloWorldTests.m; sourceTree = ""; }; + 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = HelloWorld/PrivacyInfo.xcprivacy; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HelloWorld/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = HelloWorld/AppDelegate.mm; sourceTree = ""; }; @@ -94,6 +96,7 @@ 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */, + 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */, ); name = HelloWorld; sourceTree = ""; @@ -183,7 +186,6 @@ 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, ); buildRules = ( @@ -245,6 +247,7 @@ files = ( 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 6EA01F72FAC10D00AECACF94 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -259,13 +262,14 @@ inputPaths = ( "$(SRCROOT)/.xcode.env.local", "$(SRCROOT)/.xcode.env", + "$(SRCROOT)/../.react-native.config", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\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"; + 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"; }; 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -328,23 +332,6 @@ 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; }; - C59DA0FBD6956966B86A3779 /* [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; - }; E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -433,6 +420,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld"; }; name = Debug; @@ -457,6 +445,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld"; }; name = Release; @@ -482,6 +471,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = HelloWorld; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -508,6 +498,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = HelloWorld; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; @@ -582,13 +573,8 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); - REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; + OTHER_LDFLAGS = "$(inherited) "; SDKROOT = iphoneos; - USE_HERMES = true; }; name = Debug; }; @@ -653,13 +639,8 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); - REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native"; + OTHER_LDFLAGS = "$(inherited) "; SDKROOT = iphoneos; - USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/packages/helloworld/ios/HelloWorld/PrivacyInfo.xcprivacy b/packages/helloworld/ios/HelloWorld/PrivacyInfo.xcprivacy index ef1896e70c8..41b8317f065 100644 --- a/packages/helloworld/ios/HelloWorld/PrivacyInfo.xcprivacy +++ b/packages/helloworld/ios/HelloWorld/PrivacyInfo.xcprivacy @@ -2,37 +2,36 @@ - NSPrivacyCollectedDataTypes - - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp - NSPrivacyAccessedAPITypeReasons - - C617.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategorySystemBootTime - NSPrivacyAccessedAPITypeReasons - - 35F9.1 - - - - NSPrivacyTracking - + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + diff --git a/packages/helloworld/ios/Podfile b/packages/helloworld/ios/Podfile index f091815a6dc..9cde0ddcf38 100644 --- a/packages/helloworld/ios/Podfile +++ b/packages/helloworld/ios/Podfile @@ -13,7 +13,7 @@ target 'HelloWorld' do config = use_native_modules! use_react_native!( - :path => config[:reactNativePath], + :path => "../../react-native", # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 250873f8cae..be0cb909801 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -56,6 +56,7 @@ "rn-get-polyfills.js", "scripts/compose-source-maps.js", "scripts/find-node-for-xcode.sh", + "scripts/bundle.js", "scripts/generate-codegen-artifacts.js", "scripts/generate-provider-cli.js", "scripts/generate-specs-cli.js", diff --git a/packages/react-native/scripts/bundle.js b/packages/react-native/scripts/bundle.js new file mode 100644 index 00000000000..f486f0a9412 --- /dev/null +++ b/packages/react-native/scripts/bundle.js @@ -0,0 +1,70 @@ +/** + * 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. + * + * @format + * @oncall react_native + */ + +'use strict'; + +const {bundleCommand: bc} = require('@react-native/community-cli-plugin'); +const {execSync} = require('child_process'); +const program = require('commander'); +const {existsSync, readFileSync} = require('fs'); +const path = require('path'); + +program.version( + JSON.parse( + readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf8'), + ).version, +); + +program + .name(bc.name) + .description(bc.description ?? '') + .option( + '--config-cmd ', + 'Command to generate a JSON project config', + 'npx react-native config', + ) + .option('--load-config ', 'JSON project config') + .action(async function handleAction(options, ...args) { + let config = null; + + if (options.loadConfig != null) { + const rawText = existsSync(options.loadConfig) + ? readFileSync(options.loadConfig, 'utf8') + : options.loadConfig; + config = JSON.parse(rawText); + } else if (options.configCmd != null) { + config = JSON.parse( + execSync(options.configCmd.trim(), {encoding: 'utf8'}), + ); + } + + if (config == null) { + throw new Error('No config provided'); + } + + await bc.func(args, config, options); + }); + +if (bc.options != null) { + for (const o of bc.options) { + program.option( + o.name, + o.description ?? '', + o.parse ?? (value => value), + o.default, + ); + } +} + +if (require.main === module) { + program.parse(process.argv); +} + +module.exports = program; diff --git a/packages/react-native/scripts/react-native-xcode.sh b/packages/react-native/scripts/react-native-xcode.sh index 3e1742cd8d1..08862821daa 100755 --- a/packages/react-native/scripts/react-native-xcode.sh +++ b/packages/react-native/scripts/react-native-xcode.sh @@ -90,8 +90,6 @@ fi [ -z "$NODE_ARGS" ] && export NODE_ARGS="" -[ -z "$CLI_PATH" ] && export CLI_PATH="$REACT_NATIVE_DIR/cli.js" - [ -z "$BUNDLE_COMMAND" ] && BUNDLE_COMMAND="bundle" [ -z "$COMPOSE_SOURCEMAP_PATH" ] && COMPOSE_SOURCEMAP_PATH="$REACT_NATIVE_DIR/scripts/compose-source-maps.js" @@ -139,8 +137,19 @@ if [[ $USE_HERMES != false && $DEV == false ]]; then EXTRA_ARGS+=("--minify" "false") fi -"$NODE_BINARY" $NODE_ARGS "$CLI_PATH" $BUNDLE_COMMAND \ +# Allow opting out of using npx react-native config +if [[ -n "$CONFIG_JSON" ]]; then + EXTRA_ARGS+=("--load-config" "$CONFIG_JSON") +elif [[ -n "$CONFIG_CMD" ]]; then + EXTRA_ARGS+=("--config-cmd" "$CONFIG_APP") +else + EXTRA_ARGS+=("--config-cmd" "$NODE_BINARY $NODE_ARGS $REACT_NATIVE_DIR/cli.js config") +fi + +# shellcheck disable=SC2086 +"$NODE_BINARY" $NODE_ARGS "$REACT_NATIVE_DIR/scripts/bundle.js" \ $CONFIG_ARG \ + --config-cmd "$CONFIG" \ --entry-file "$ENTRY_FILE" \ --platform "$BUNDLE_PLATFORM" \ --dev $DEV \