xref: /expo/packages/@expo/cli/src/run/ios/runIosAsync.ts (revision 75a300d7)
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