Today we're going to take a look at how we can control (and interact with) the iOS Simulator from the command line.

There's no need to install anything new though. The tool we're going to be using is already on our Mac, hiding inside the xcrun command, which gets installed with Xcode.

It's called simctl.

Let's begin!

First thing we'll want to do is tell simctl to print out a list of our current iOS Simulator devices. We can do that by running:

xcrun simctl list devices

This will print a list of all the simulated devices and a UDID value with each:

-- iOS 10.3 --
iPhone 7 (C4481459-5BB1-4CE1-9BE0-CF0FEA351299) (Booted)
iPhone 7 Plus (ADCB6F99-5ADD-49B1-83AE-5391D845C4D0) (Shutdown)
iPhone SE (FB0899C0-5812-492E-80D9-9DE517554C12) (Shutdown)
iPad Pro (9.7 inch) (45F47977-9A03-4DD1-8FD0-289F7936FE98) (Shutdown)
iPad Pro (10.5-inch) (C3C909DC-BF70-4D67-BF7E-A41A0CF4AF56) (Shutdown)

We can see by the (Booted) notation next to the first device that simctl has identified the iOS Simulator we had open at the time of running the command.

We can pass that UDID (C4481459-5BB1-4CE1-9BE0-CF0FEA351299) to other commands to target our currently running iOS Simulator.

For shorthand though, we can also just pass the term booted to target the currently running iOS Simulator.

(Note that in Xcode 9 multiple iOS Simulators can be running at once. If we pass booted in this case, simctl will just choose one for us).

Whew. Ok with that introduction out of the way let's try this thing out.

First up, one of the best features of simctl, opening URLs.

To open a URL in the iOS Simulator, from the command line, all we need to run is:

xcrun simctl openurl booted ""

If we look at our iOS Simulator after running that, we'll see Safari open up and load the page.


Even better, this works just as well with custom URL schemes:

xcrun simctl openurl booted "spaceships://ships/123"

Very cool.

Next, let's add some photos and videos.

We can use the addmedia subcommand to import media to the iOS Simulator:

xcrun simctl addmedia booted ~/Desktop/images/image1.png ~/Desktop/images/image2.jpg ~/Desktop/images/image3.jpg

We can include one or more file paths here. It supports images, videos, and even Live Photos.

After running, the files will be imported and appear in the Photo Library:

Next: iCloud Syncing.

We can explicitly force a sync of iCloud using this command:

xcrun simctl icloud_sync booted

What's nice about this is we'll even get errors printed if (for example) iCloud isn't yet configured in this simulated device:

An error was encountered processing the command (domain=BRCloudDocsErrorDomain, code=2):
The operation couldn’t be completed.
(BRCloudDocsErrorDomain error 2 - Logged out - iCloud Drive is not configured)

This next one's a doozy. We can use simctl to record and stream live video, and capture screenshots of any screen of our iOS Simulator.

First let's grab a screenshot:

xcrun simctl io booted screenshot ~/Desktop/screenshot.png

Neat. Easy enough, next let's try recording a movie:

xcrun simctl io booted recordVideo --type=mp4 ~/Desktop/movie.mp4

Full quality movie file is available here, for the curious.

The recordVideo subcommand's output can be | (piped) into other commands or even to a TCP or UDP socket for live streaming. This works on all iOS, tvOS, and even watchOS Simulators. Very cool.

Last but not least, we can print out the path for app's installation directory on disk:

xcrun simctl get_app_container booted


To save us a step, we can | (pipe) that path output to pbcopy to put the value on our clipboard for easy pasting later:

xcrun simctl get_app_container booted | pbcopy

There's plenty more that simctl can do. To see the long list of available commands and features, we can run:

xcrun simctl

We can add, remove and even reset/erase simulated devices, interact with a device's pasteboards, launch apps with environment variables and much more.

That's all for now, happy simulating!

-- Update: Tuesday July 25th, 2017 --

Friend of the pod Bites? (and creator of the fantastic Fastlane suite of tools, (Bites)) Felix Krause writes in with a great addition regarding the --json flag:

We can pass the --json (-j for shorthand) flag to any of the simctl commands that print information to print it in JSON format.

This is perfect for | (pipe)-ing to other commands, or for consumption by a host process/program:

xcrun simctl list runtimes --json
  "runtimes" : [
      "buildversion" : "14E8301",
      "availability" : "(available)",
      "name" : "iOS 10.3",
      "identifier" : "",
      "version" : "10.3.1"
      "buildversion" : "14V243",
      "availability" : "(available)",
      "name" : "watchOS 3.2",
      "identifier" : "",
      "version" : "3.2"