iOS Setup — Xcode, Simulators, Real Devices

9 min read

iOS automation with Appium runs exclusively on macOS. There is no way around this — Xcode, which Appium relies on through WebDriverAgent, is macOS-only software. If your CI infrastructure is Linux-only, you need a macOS agent for iOS tests. This lesson covers the full setup from Xcode installation through running your first session against a Simulator and a real device.

Install Xcode

Install Xcode from the Mac App Store. It is large (10–15 GB) and takes time. After installation:

# Accept the Xcode license
sudo xcodebuild -license accept
 
# Verify installation
xcode-select -p
# Should return: /Applications/Xcode.app/Contents/Developer
 
# Install command line tools if needed
xcode-select --install

Check the Xcode version:

xcodebuild -version

Appium's XCUITest driver has a minimum Xcode version requirement — check the driver's release notes. At the time of writing, Xcode 15+ is recommended.

iOS Simulators

Xcode ships with several Simulator runtimes. To see what's installed:

xcrun simctl list devices available

To install additional runtime versions, open Xcode → Settings → Platforms and download the iOS versions you need.

Starting a Simulator via command line

# List all devices with their UDIDs
xcrun simctl list devices
 
# Boot a specific Simulator
xcrun simctl boot "iPhone 15 Pro"
 
# Open the Simulator app (required to see the UI)
open -a Simulator
 
# Shutdown
xcrun simctl shutdown "iPhone 15 Pro"
 
# Erase all content (clean state)
xcrun simctl erase "iPhone 15 Pro"

Installing an app on a Simulator

xcrun simctl install booted /path/to/MyApp.app

Note: .app bundles (not .ipa) are used for Simulators. An .ipa is a signed archive for real devices. If your build system only outputs .ipa, extract the .app from inside it:

unzip MyApp.ipa -d extracted/
# The .app bundle is at extracted/Payload/MyApp.app

Appium capabilities for a Simulator

XCUITestOptions options = new XCUITestOptions();
options.setPlatformVersion("17.2");
options.setDeviceName("iPhone 15 Pro");
options.setApp("/absolute/path/to/MyApp.app");
 
IOSDriver driver = new IOSDriver(new URL("http://127.0.0.1:4723"), options);

The deviceName must match the Simulator name exactly as shown by xcrun simctl list devices. Appium will boot the Simulator if it is not already running.

Real device setup

Real iOS devices require more configuration because Apple's code signing must be satisfied.

Prerequisites

  1. An Apple Developer account (free accounts work with limitations; a paid $99/year Developer Program membership gives full access)
  2. Xcode signed in to your Apple ID: Xcode → Settings → Accounts → Add Apple ID
  3. The device UDID

Find the device UDID

Connect the device via USB. Open Xcode → Window → Devices and Simulators. The UDID is shown next to the device name. Copy it.

Alternatively:

xcrun xctrace list devices

Create a provisioning profile for WebDriverAgent

Appium installs its own automation agent (WebDriverAgent) on your real device. WDA must be signed with a valid certificate. The simplest way:

  1. Open Terminal: open $(appium driver doctor xcuitest --extra-capability wdaLocalPort 2>/dev/null || find ~/.nvm ~/.npm -name "WebDriverAgent.xcodeproj" 2>/dev/null | head -1 | xargs dirname)
    Or find it directly: find / -name "WebDriverAgent.xcodeproj" 2>/dev/null | head -1
  2. Open WebDriverAgent.xcodeproj in Xcode
  3. Select the WebDriverAgentLib and WebDriverAgentRunner targets
  4. Under Signing & Capabilities, set your Team to your Apple ID
  5. Change the Bundle Identifier to something unique (e.g., com.yourname.WebDriverAgentRunner)
  6. Build the target once to verify signing works

Appium capabilities for a real device

XCUITestOptions options = new XCUITestOptions();
options.setUdid("00008101-001A2B3C4D5E6F78");   // exact UDID
options.setPlatformVersion("17.2");
options.setApp("/absolute/path/to/MyApp.ipa");
options.setXcodeOrgId("ABCDE12345");             // your Team ID from developer.apple.com
options.setXcodeSigningId("iPhone Developer");
 
IOSDriver driver = new IOSDriver(new URL("http://127.0.0.1:4723"), options);

Granting permissions via simctl

Pre-granting permissions on a Simulator avoids dialog interruptions during tests:

# Grant location permission
xcrun simctl privacy booted grant location com.example.myapp
 
# Grant camera permission
xcrun simctl privacy booted grant camera com.example.myapp
 
# Reset all permissions (use before a clean test run)
xcrun simctl privacy booted reset all com.example.myapp

Appium's appium-doctor check for iOS

appium-doctor --ios

Common red flags and fixes:

IssueFix
Xcode not foundInstall from App Store, run sudo xcodebuild -license accept
libimobiledevice missingbrew install libimobiledevice
ios-deploy missingbrew install ios-deploy (required for real devices)
carthage missingbrew install carthage (needed for older WDA builds)

Choosing between Simulator and real device

Use a Simulator for daily development, CI regression, and anything that does not require hardware. Use a real device for:

  • App Store sign-off testing
  • Face ID / Touch ID flows (even then, the Simulator can mock the result)
  • Push notification delivery verification
  • In-app purchases
  • NFC-dependent features
  • Accurate memory and battery behaviour

// tip to track lessons you complete and pick up where you left off across devices.