diff --git a/.changeset/many-flies-reply.md b/.changeset/many-flies-reply.md new file mode 100644 index 000000000..616726201 --- /dev/null +++ b/.changeset/many-flies-reply.md @@ -0,0 +1,5 @@ +--- +'@rock-js/plugin-brownfield-ios': minor +--- + +feat: copy React Native prebuilt frameworks diff --git a/packages/platform-apple-helpers/src/lib/utils/pods.ts b/packages/platform-apple-helpers/src/lib/utils/pods.ts index cfe5874a0..f9c2e1966 100644 --- a/packages/platform-apple-helpers/src/lib/utils/pods.ts +++ b/packages/platform-apple-helpers/src/lib/utils/pods.ts @@ -124,15 +124,30 @@ async function runPodInstall(options: { fs.rmSync('build', { recursive: true }); } - const shouldHandleRepoUpdate = options?.shouldHandleRepoUpdate || true; - const loader = spinner({ indicator: 'timer' }); - loader.start('Installing CocoaPods dependencies'); const reactNativeVersion = await getReactNativeVersion(options.projectRoot); const isReactNative81OrHigher = versionCompare(reactNativeVersion, '0.81.0') >= 0; + const isReactNative84OrHigher = + versionCompare(reactNativeVersion, '0.84.0') >= 0; + + // below: starting from RN 0.84, Apple prebuilts are used by default; before this version, + // they need to be explicitly enabled + // ref: https://github.com/facebook/react-native/commit/df9d31b2435255f799aa024ffb0f87bcdb665645 const usePrebuiltReactNative = Boolean( - !options.brownfield && isReactNative81OrHigher && options.usePrebuiltRNCore, + isReactNative81OrHigher && + (options.usePrebuiltRNCore ?? isReactNative84OrHigher), + ); + + logger.info( + usePrebuiltReactNative + ? 'Using prebuilt React Native' + : 'Building React Native from source', ); + + const shouldHandleRepoUpdate = options?.shouldHandleRepoUpdate || true; + const loader = spinner({ indicator: 'timer' }); + loader.start('Installing CocoaPods dependencies'); + const command = options.useBundler ? 'bundle' : 'pod'; const args = options.useBundler ? ['exec', 'pod', 'install'] : ['install']; try { diff --git a/packages/plugin-brownfield-ios/src/lib/copyReactXcframeworks.ts b/packages/plugin-brownfield-ios/src/lib/copyReactXcframeworks.ts new file mode 100644 index 000000000..181b98e02 --- /dev/null +++ b/packages/plugin-brownfield-ios/src/lib/copyReactXcframeworks.ts @@ -0,0 +1,63 @@ +import fs, { existsSync } from 'node:fs'; +import path from 'node:path'; +import { color, logger, spinner } from '@rock-js/tools'; + +export function copyReactXcframeworks({ + sourceDir, + destinationDir, +}: { + sourceDir: string; + destinationDir: string; +}) { + const react = 'React.xcframework'; + const reactNativeDependencies = 'ReactNativeDependencies.xcframework'; + const loader = spinner(); + + const reactFrameworkSource = path.join( + sourceDir, + `Pods/React-Core-prebuilt/${react}`, + ); + + const reactNativeDepsSource = path.join( + sourceDir, + `Pods/ReactNativeDependencies/framework/packages/react-native/${reactNativeDependencies}`, + ); + + if (existsSync(reactFrameworkSource)) { + loader.start(`Copying ${color.bold(react)}`); + const reactDestination = path.join(destinationDir, react); + + if (existsSync(reactDestination)) { + logger.debug(`Removing old ${react} copy`); + fs.rmSync(reactDestination, { recursive: true, force: true }); + } + + fs.cpSync(reactFrameworkSource, reactDestination, { + recursive: true, + force: true, + }); + + loader.stop(`Copied ${color.bold(react)}`); + } + + if (existsSync(reactNativeDepsSource)) { + loader.start(`Copying ${color.bold(reactNativeDependencies)}`); + + const reactNativeDepsDestination = path.join( + destinationDir, + reactNativeDependencies, + ); + + if (existsSync(reactNativeDepsDestination)) { + logger.debug(`Removing old ${reactNativeDependencies} copy`); + fs.rmSync(reactNativeDepsDestination, { recursive: true, force: true }); + } + + fs.cpSync(reactNativeDepsSource, reactNativeDepsDestination, { + recursive: true, + force: true, + }); + + loader.stop(`Copied ${color.bold(reactNativeDependencies)}`); + } +} diff --git a/packages/plugin-brownfield-ios/src/lib/pluginBrownfieldIos.ts b/packages/plugin-brownfield-ios/src/lib/pluginBrownfieldIos.ts index e5a34e032..1dbe3343e 100644 --- a/packages/plugin-brownfield-ios/src/lib/pluginBrownfieldIos.ts +++ b/packages/plugin-brownfield-ios/src/lib/pluginBrownfieldIos.ts @@ -12,6 +12,7 @@ import { } from '@rock-js/platform-apple-helpers'; import { colorLink, intro, logger, outro, relativeToCwd } from '@rock-js/tools'; import { copyHermesXcframework } from './copyHermesXcframework.js'; +import { copyReactXcframeworks } from './copyReactXcframeworks.js'; const buildOptions = getBuildOptions({ platformName: 'ios' }); @@ -35,6 +36,7 @@ export const packageIosAction = async ( pluginConfig?: IOSProjectConfig, ) => { intro('Packaging iOS project'); + logger.setVerbose(args.verbose ?? false); // 1) Build the project const iosConfig = getValidProjectConfig('ios', projectRoot, pluginConfig); @@ -116,7 +118,13 @@ export const packageIosAction = async ( reactNativeVersion, }); - // 5) Inform the user + // 5) Copy React and ReactNativeDependencies xcframeworks to the output path + copyReactXcframeworks({ + sourceDir, + destinationDir: frameworkTargetOutputDir, + }); + + // 6) Inform the user logger.log( `XCFrameworks are available at: ${colorLink( relativeToCwd(frameworkTargetOutputDir),