1import chalk from 'chalk'; 2 3import * as XcodeBuild from './XcodeBuild'; 4import { Options } from './XcodeBuild.types'; 5import { launchAppAsync } from './launchApp'; 6import { resolveOptionsAsync } from './options/resolveOptions'; 7import * as Log from '../../log'; 8import { maybePromptToSyncPodsAsync } from '../../utils/cocoapods'; 9import { setNodeEnv } from '../../utils/nodeEnv'; 10import { ensurePortAvailabilityAsync } from '../../utils/port'; 11import { profile } from '../../utils/profile'; 12import { getSchemesForIosAsync } from '../../utils/scheme'; 13import { ensureNativeProjectAsync } from '../ensureNativeProject'; 14import { logProjectLogsLocation } from '../hints'; 15import { startBundlerAsync } from '../startBundler'; 16 17export async function runIosAsync(projectRoot: string, options: Options) { 18 setNodeEnv(options.configuration === 'Release' ? 'production' : 'development'); 19 require('@expo/env').load(projectRoot); 20 21 assertPlatform(); 22 23 const install = !!options.install; 24 25 if ((await ensureNativeProjectAsync(projectRoot, { platform: 'ios', install })) && install) { 26 await maybePromptToSyncPodsAsync(projectRoot); 27 } 28 29 // Resolve the CLI arguments into useable options. 30 const props = await resolveOptionsAsync(projectRoot, options); 31 32 // Spawn the `xcodebuild` process to create the app binary. 33 const buildOutput = await XcodeBuild.buildAsync(props); 34 35 // Find the path to the built app binary, this will be used to install the binary 36 // on a device. 37 const binaryPath = await profile(XcodeBuild.getAppBinaryPath)(buildOutput); 38 39 // Ensure the port hasn't become busy during the build. 40 if (props.shouldStartBundler && !(await ensurePortAvailabilityAsync(projectRoot, props))) { 41 props.shouldStartBundler = false; 42 } 43 44 // Start the dev server which creates all of the required info for 45 // launching the app on a simulator. 46 const manager = await startBundlerAsync(projectRoot, { 47 port: props.port, 48 headless: !props.shouldStartBundler, 49 // If a scheme is specified then use that instead of the package name. 50 scheme: (await getSchemesForIosAsync(projectRoot))?.[0], 51 }); 52 53 // Install and launch the app binary on a device. 54 await launchAppAsync(binaryPath, manager, { 55 isSimulator: props.isSimulator, 56 device: props.device, 57 shouldStartBundler: props.shouldStartBundler, 58 }); 59 60 // Log the location of the JS logs for the device. 61 if (props.shouldStartBundler) { 62 logProjectLogsLocation(); 63 } 64} 65 66function assertPlatform() { 67 if (process.platform !== 'darwin') { 68 Log.exit( 69 chalk`iOS apps can only be built on macOS devices. Use {cyan eas build -p ios} to build in the cloud.` 70 ); 71 } 72} 73