Xcode Simulator App Advanced
In this tutorial, you’ll learn about Xcode Simulator’s advanced features to improve your daily development experience.
Version
- Swift 5, iOS 14, Xcode 12

The Xcode Simulator is one of the tools used most widely by developers. Running and testing apps on the simulator has become part of every developer’s daily routine. Becoming familiar with various simulator options is vital for any developer. Did you know you can create and configure simulators from the command line as well? In this tutorial, you’ll learn:
- What a simulator is
- Insights into useful simulator options
- To create and configure simulators from the command line
- To stream and capture logs using the command line
- To create a Bash script to automate launching the app on a simulator in different locales.
Getting Started
Download the project by clicking the Download Materials button at the top or bottom of this page. Open the RayWonders project. Build and run.
This app has two tabs — Photo and Map. The Photo tab shows photos of the wonders of the world. Tapping a photo shows a detailed view of its description. The Map tab shows the photos of the wonders of the world as annotations on a map. This is one of the rare raywenderlich.com tutorials where you won’t be modifying the project. Instead, you’ll use this app as a foundation to learn the various simulator options. Before you embark on your world tour, you’ll need to understand what a simulator is.
What Is a Simulator?
The simulator is a great tool to simulate iOS, iPadOS, tvOS, and watchOS on the Mac. It helps rapid prototyping and testing builds by simulating different devices. At a more technical level, a simulator is a separate user space running on the macOS kernel.
User space is the system memory allocated to run applications, whereas kernel space is the system memory allocated to run the OS kernel and device drivers. Launching a new simulator creates a separate user space.
The kernel is a core component of the OS. It facilitates interactions between the hardware and software components. It’s responsible for managing the hardware, allocating memory and arbitrating between processes.
One of those processes — Daemon — runs in the background. launchd, cfprefsd, distnoted are some of the system daemons.
Are running an app on a device and on a simulator the same? You’ll learn that next.
Running App on a Device vs. a Simulator
Testing apps on a simulator is very handy. However, there are a few key differences between running apps on a device and on a simulator.
Computing Performance
Simulators share the same computing resources with the Mac. This includes memory, CPU and network connection. In contrast, physical devices have less memory and computing power compared with a Mac. Also, the network can be one unpredictable beast on the physical device.
Display
The resolution and the color gamut on a Mac and the physical device can differ, causing images and text to appear jagged. You’ll learn how to simulate the exact physical device size later in this tutorial.
Hardware Limitations
Some hardware components are not supported in a simulator. These include:
- Bluetooth
- Camera
- Motion sensors such as accelerometer and gyroscope
- Proximity sensor
Framework Limitations
A few frameworks are not supported in simulator. These include:
- ARKit
- HomeKit
- IOSurface
- MessageUI
For a more exhaustive list of all the differences, please refer to the documentation by selecting Help ▸ Simulator Help in the Simulator menu.
Next, you’ll learn how to organize the simulators.
Organizing Simulators Using Xcode
Xcode ships with a default set of simulators. To view a list of these simulators, follow these steps:
- Open Xcode.
- Select the Window menu option.
- Choose the Devices and Simulators menu.
- Select the Simulators tab.
You’ll see a list of simulators that were shipped with Xcode. If you’ve downloaded other runtimes in the past, you’ll see those associated simulators as well.
Now, you’ll create a new simulator with a custom name.
Follow these steps:
- Press the + button at the bottom left.
- Set the simulator name as Demo.
- Select iPhone 12 Pro as the device type.
- Select iOS 14.2 as the OS version.
- Press Create.
This creates a new simulator with the name Demo, which you can now find in the list of simulators.
Uncheck the Show as runtime destination checkbox for the Demo simulator.
This hides the simulator. It won’t show up in the list of simulators next to the app scheme.
Control-click the Demo simulator. Several options appear, such as Delete and Rename.
Go ahead and delete the Demo simulator by clicking Delete. Don’t worry; you’ll create it using a different method very soon.
Running Older Runtimes
Sometimes you’ll have to run your app on older versions of runtimes.
You can download older runtimes by selecting Download more runtimes in the OS Version drop-down when creating a new simulator.
You can also download more runtimes from the Components window. Select Xcode ▸ Preferences ▸ Components option.
This window shows the list of the downloaded simulator runtime as well as other runtimes available for download.
Next, you’ll learn an alternative way to create simulators.
Creating Simulators From the Simulator Menu
Build and run.
When the simulator is running, follow these steps:
- Select File ▸ New Simulator from the Simulator menu.
- Enter Demo as the simulator name.
- Select iPhone 12 Pro as the Device Type.
- Select iOS 14.2 as the version.
- Click Create.
Open the simulator by following these steps:
- Select File ▸ Open Simulator from the menu.
- Select the iOS 14.2 run time.
- Choose the Demo simulator.
This launches the Demo simulator.
That was fast and easy! Next, you’ll learn about the various size options in the simulator.
Comparing Simulator Size Options
You can resize a simulator by clicking and dragging from one of the four corners. The Window menu options provide four scaling options.
Physical Size
Physical size resizes the simulator to match the actual device size. This visualizes how your app looks across different screen sizes.
Point Accurate
Point accurate mode sizes the window so that the content has the same size on devices with different scale factors. As a result, an image on a device with a 3x display appears with the same size as a 2x display.
Pixel Accurate
In this mode, the window size changes to the same number of pixels as the physical device. Each pixel on the simulated device maps to one pixel on your Mac’s display. This causes simulators to appear larger on screen if your Mac’s display has a lower pixel density than the simulated device. You can use this mode to check the alignment of images and controls in your app.
Fit Screen
This resizes the simulator to the size of your Mac display.
Next, you’ll learn the various options provided in a simulator.
Slow Animations
Animations are an integral part of an app experience. Build and run RayWonders in the Demo simulator.
Tap the Photos tab. Next, tap a picture of one of the wonders of the world to present a view of details about the place. Dismiss the view by sliding it down.
To simulate slow animations, select the Debug ▸ Slow Animations option in the Simulator menu.
Tap the picture again. The view now animates slowly.
Viewing the animations slowly can help bring clarity. In addition, it can help in examining problems in rendering and performance.
Next, you’ll learn to simulate Dark Mode. Before proceeding, disable the slow animations by deselecting the Debug ▸ Slow Animations menu option.
Dark Mode
Dark Mode provides a great viewing experience in low-light environments. The simulator provides an option to view your app in Dark Mode.
Select Features ▸ Toggle Appearance. This toggles the appearance to Dark Mode. Now, tap the Map tab in RayWonders.
You’ll notice that the map has changed to a dark appearance. Easy, isn’t it? This is a handy way to test your app in Dark Mode.
To change the appearance back to default, deselect Features ▸ Toggle appearance. To learn how to support Dark Mode, check out Supporting Dark Mode: Adapting You App to Support Dark Mode tutorial.
Next, you’ll learn how to simulate push notifications!
Simulating Push Notifications
Push notifications are a great way to let your users know of new content updates in your app. In the past, testing push notifications was a challenge. You needed a physical device to test the push notifications. Starting with Xcode 11.4, you can simulate push notifications on a simulator.
Create a file named RayWondersPushNotification.apns using the following:
{
"Simulator Target Bundle": "com.raywenderlich.RayWonders",
"aps": {
"alert": {
"title": "Hindi language support added!",
"body": "Checkout RayWonders in Hindi!"
}
}
}
This is a simple, visible push notification payload with a title
and a body
. The Simulator Target Bundle
is a special key. It specifies the bundle ID of the app that should receive the notification.
Before trying the payload, you need to first grant the notification permission in the app.
Follow these steps:
- Open RayWonders in the Demo simulator.
- Tap the bell icon on the top right in the Photos tab.
- Select Allow in the notification permission prompt.
- Select Device ▸ Home from the Simulator menu to put the app in the background.
Next, drag and drop RayWondersPushNotification.apns file on the Demo simulator.
Ta-da! A visible push notification appears. That was easy! Bear in mind that a simulator can only simulate a push notification. To test an actual push notification received from the Apple push notification server requires a physical device.
To learn about push notifications in more depth, read this Push Notifications Tutorial: Getting Started.
Next, you’ll learn how to zoom.
Zooming In and Out
Open RayWonders in the simulator. Switch to the Map tab. The map is centered and zoomed in on a wonder of the world. Where are the other wonders of the world?
You’ll need to zoom out to see the world view. Click and drag while holding down the Option key.
Clicking and dragging is great, but it can soon get tiresome. Next, you’ll learn a quicker way to go to a location.
Simulating a Location
The simulator provides an easy way to simulate a location. First, you need to grant location permissions in RayWonders.
Follow these steps:
- Open RayWonders in the simulator and switch to the Map tab.
- Tap the Start Location Services button in the Map tab.
- Select the Allow While Using App permission.
Now, to simulate location:
- Select Features ▸ Location ▸ Custom Location from the Simulator menu.
- Enter 41.8902142 as the latitude and 12.4900422 as the longitude.
- Click OK.
This takes you directly to the Colosseum on the map — your fastest journey ever!
However, entering the coordinates for each location to simulate is quite a memory-intensive — your memory, that is — task. Next, you’ll learn an easier solution to this problem.
Sharing Locations From the Maps App
The Maps app on macOS provides an easy way to share locations with your simulator.
Follow these steps:
- Open the Maps app.
- Enter Machu Picchu in the search text.
- Click the Share button next to the search field.
- Choose Simulator from the drop-down.
- In the location prompt, select Demo as the simulator.
- Click Send.
You’re now in Machu Picchu in the simulator’s map view.
Congratulations! You’ve just created a world record as the fastest traveler from the Colosseum to Machu Picchu! :]
To learn about handling location in your app in more depth, check out MapKit and Core Location.
Now, it’s time to shake things up.
Simulating Shake Gesture
Shake gestures are great cues to prompt the user to give feedback in an app. But how can you shake a simulator? Thankfully, shaking the Mac rigorously is not the solution. The simulator provides an easy way.
Open RayWonders on the Demo simulator. Select Device ▸ Shake from the Simulator menu.
This simulates a shake gesture.
RayWonders detects the shake and prompts an alert to the user. You can detect and handle shake gestures in your app by implementing the method motionEnded(_:with:)
. To learn more, check out the Apple documentation.
Next, you’ll learn how to simulate a memory warning.
Simulating a Memory Warning
iOS sends a warning to the app when its memory usage approaches the upper limit on the device. The app needs to respond by purging the cache data, which can be re-created later.
Open RayWonders on the Demo simulator. Select Debug ▸ Simulate Memory Warning from the menu.
This simulates a memory warning.
RayWonders shows an alert. You can learn more about handling memory warnings in this Responding to Memory Warnings Apple documentation.
So far, you’ve seen some useful simulator options. There are several others that aren’t covered in this tutorial. You should check them out, depending on your app needs. Some of these options include:
- Simulate iCloud sync using Features ▸ Trigger iCloud Sync.
- Simulate Apple Pay authorization using Features ▸ Authorize Apple Pay.
- Trigger Siri using Device ▸ Siri.
- Check System Log using Debug ▸ Open System Log.
Next, you’ll learn to interact with simulators using the command line.
Organizing Simulators Using the Command Line
So far, you’ve created and managed simulators using Xcode. In addition, you’ve also learned the various Simulator menu options. Now, you’ll learn to manage and use simulators from the command line.
Open Terminal. Enter the following command:
xcrun simctl --help
and press Enter.
The help option provides the list of all the subcommands available using simctl.
Simctl is a tool to help manage and programmatically interface with the simulator. You can access simctl using the xcrun command-line tool.
Now, you’ll explore several of these subcommands. Run the following:
xcrun simctl list
The list command shows the list of all the available devices and the runtimes.
It also shows the current state of the devices, whether it’s Booted or Shutdown.
Next, you’ll learn to create and launch a simulator from the command line.
Creating Simulator From the Command Line
Before creating a new simulator, delete the Demo simulator created via Xcode. Enter the following:
xcrun simctl delete Demo
The delete command identifies a simulator and deletes it. Now, create a new simulator from the command line.
Enter the following:
xcrun simctl create Demo "iPhone 12 Pro" "iOS14.2"
The create command takes in a device type and runtime and creates a simulator. This creates an iPhone 12 Pro simulator with iOS 14.2 runtime.
Now, Terminal shows the unique identifier of the new device.
Enter the following:
xcrun simctl boot Demo
The starts the Demo simulator. By default, it’s in the Shutdown state.
Now, install RayWonders using the command line. You’ll first need the app bundle. Follow these steps:
- Open the Project navigator and select RayWonders.app, located in the Products folder.
- Right-click and select Show in Finder.
- Copy RayWonders to your home directory.
Open Terminal and navigate to the home directory by entering the following:
cd ~
Next, run the following:
xcrun simctl install Demo RayWonders.app
The install
command installs RayWonders on the simulator. Great job!
You can even launch the app using simctl. Enter the following:
xcrun simctl launch Demo com.raywenderlich.RayWonders
The launch command takes the app bundle ID as a parameter. RayWonders launches in the Demo simulator.
Congratulations! You’ve now created, booted, installed and launched a simulator from the command line. Here are some other options you can try:
- terminate: This terminates an application using the bundle identifier.
- erase: This erases the device contents.
- uninstall: This uninstalls the application. You’ll need to specify the bundle identifier of the application.
Next, you’ll learn some cool commands that are available for your app.
Taking Screenshots
Screenshots of your app can be useful in several scenarios. For instance, you’ll need screenshots when submitting your app in AppStore.
Enter the following command:
xcrun simctl io Demo screenshot screenshot.png --type="png"
This takes a screenshot of the current screen and saves it to the file screenshot.png. In addition to a png, screenshot
command supports other file formats, such as TIFF, BMP, GIF and JPEG.
A screenshot can show what your app looks like, and a picture is worth a thousand words. However, a video is worth a lot more. :]
Recording Video
You can record videos of your app using simctl. To start recording, enter the following command:
xcrun simctl io Demo recordVideo Demo.mov --codec="h264"
Interact with RayWonders on the simulator. Press Control-C in the terminal when you have finished. This saves the video in Demo.mov.
In addition, you can specify the desired codec when recording. The default codec is hevc.
The recordVideo
command helps avoid using a QuickTime player to record a video of your app.
Customizing the Status Bar
Check the app’s status bar in the simulator. You can see that the battery is full, the device has the best signal and the time on the simulator is your local Mac time. What do you do if you want to override these?
Enter the following command in Terminal:
xcrun simctl status_bar Demo override \
--dataNetwork 4g --cellularBars 2 --batteryState charging \
--batteryLevel 25 --time 12:05
This overrides the status bar to set:
- Data network as 4G
- Cellular signal to two bars
- Battery state to charging and the battery level to 25%
- Time on the simulator to 12:05
When you do this in your own project, you can set the status bar information to whatever you want.
The status_bar
command can be really handy when you want to customize the appearance of your app screenshots and videos.
When you are done, revert the status bar to the default appearance by entering the following:
xcrun simctl status_bar Demo clear
Debugging and Diagnosing
Simctl also provides several commands to help debug and diagnose issues.
Go back to Terminal, and enter the following:
xcrun simctl get_app_container Demo com.raywenderlich.RayWonders
get_app_container
prints the app bundle’s path.
You can inspect the data within the app container using this path. In addition, your simulator logs can be really useful when debugging issues.
Now, type the following in Terminal:
xcrun simctl spawn Demo log stream
This starts streaming all the logs from the Demo simulator.
However, this can be too much data to inspect. Press Control-C to stop the stream.
Try the following:
xcrun simctl spawn Demo log stream | grep com.raywenderlich.RayWonders
This filters the logs and displays only those from RayWonders.
As you interact with the app, you’ll see more logs displayed in the terminal. These logs can be extremely useful when filing a bug or providing feedback to Apple.
Type the following:
xcrun simctl diagnose
The diagnose
command collects a bunch of data, including logs and crashes. It also generates files that can help Apple debug issues. By default, the collected logs are for the booted device. By specifying the UDID of a device, you can constrain the collection of logs to that particular device.
You’ve now become a simulator command line expert! You can take it a step further by automating common actions using Bash scripts.
Automating Using a Bash Script
Now, you’ll create a script to clone a simulator and launch RayWonders in a different locale.
First, open Terminal, and enter the following:
touch sim_utility.sh
This creates a new file with the name sim_utility. The .sh extension denotes that it’s a shell script.
Next, run:
chmod +x sim_utility.sh
This makes the sim_utility.sh executable so you can run it.
Open sim_utility.sh in an editor, and add the following:
#!/bin/bash
#1
COMMAND="$1"
SIMULATOR_NAME="$2"
#2
get_id_of_simulator() {
#TODO
}
get_status_of_simulator() {
#TODO
}
launch() {
#TODO
}
#3
case $COMMAND in
"launch") launch "$3" "$4" "$5" ;;
*)
launch_help
exit 1
;;
esac
Here’s what’s going on:
- The script takes in a command name and a simulator name as the command line parameters.
-
get_id_of_simulator
,get_status_of_simulator
andlaunch
are empty stubs that you’ll implement next. - The script currently supports one command named
launch
. Thelaunch
takes three additional parameters, which you’ll implement soon.
In get_id_of_simulator
, replace #TODO
with the following:
xcrun simctl list | grep "$SIMULATOR_NAME" | \
awk 'match($0, /\(([-0-9A-F]+)\)/) {print substr( $0, RSTART + 1, RLENGTH-2 )}'
get_id_of_simulator
searches the list of a simulators to match the name specified as a parameter. If it finds a match, the substring operation gets the unique identifier of the simulator.
In the get_status_of_simulator
method, replace #TODO
with the following:
xcrun simctl list | grep "$SIMULATOR_NAME" | \
awk 'match($0, /\(([a-zA-Z]+)\)/) {print substr( $0, RSTART + 1, RLENGTH - 2 )}'
get_status_of_simulator
searches for a simulator with a matching name in the list of devices. If it finds a match, it gets the status of the simulator — booted or shutdown. You’ll use these in the launch
.
Implementing Launch
In launch
, replace #TODO
with the following:
#1
BUNDLE_ID="$1"
LOCALE="$2"
LANGUAGE="$3"
CLONE_NAME="$LOCALE"
#2
SIMULATOR_ID=$(get_id_of_simulator)
if [ -z "$SIMULATOR_ID" ]; then
echo "No device matching the name: $SIMULATOR_NAME"
return
fi
echo "Simulator id: $SIMULATOR_ID"
echo "Bundle id: $BUNDLE_ID"
echo "Locale: $LOCALE"
#3
SIMULATOR_STATUS=$(get_status_of_simulator)
echo "Simulator Status: $SIMULATOR_STATUS"
if [ "$SIMULATOR_STATUS" = "Booted" ]; then
echo "Making sure the device is shutdown first..."
xcrun simctl shutdown "$SIMULATOR_NAME"
fi
#4
echo "Cloning the device with name $LOCALE..."
xcrun simctl clone "$SIMULATOR_NAME" "$CLONE_NAME"
#5
echo "Booting device..."
xcrun simctl boot "$SIMULATOR_NAME"
xcrun simctl boot "$CLONE_NAME"
#6
echo "Launching app..."
xcrun simctl launch "$SIMULATOR_NAME" "$BUNDLE_ID"
#7
xcrun simctl launch "$CLONE_NAME" "$BUNDLE_ID" -AppleLocale "$LOCALE" \
-AppleLanguages "($LANGUAGE)"
Save the file. Here’s what this does, step by step. It:
- Gives additional parameters to
launch
, including the bundle ID of the application, the locale and the language to launch your app in. It declares a local variableCLONE_NAME
, which is the name of the cloned device. In this case, the name of the cloned device is the locale you specify; - Fetches the simulator’s ID by calling
get_id_of_simulator
. Then, it stores the result inSIMULATOR_ID
. If there is no matching simulator, it exits the program; - Fetches the simulator’s status by calling
get_status_of_simulator
. If the status isBooted
, it runs theshutdown
command to shut it down. To be cloned, a device must be shut down; - Clones the simulator using the
clone
command; - Boots both the original simulator and the cloned simulator using the
boot
command; - Launches the app on the original simulator using the
launch
command; - Launches the app using the
launch
command on the cloned simulator. It specifies the locale and language for the app to launch in.
Launching RayWonders in a Different Locale
Open Terminal, and run the following:
./sim_utility.sh launch Demo com.raywenderlich.RayWonders hi_IN hi
RayWonders launches in Hindi on a cloned simulator with the name hi_IN.
No more going to the settings and switching the device language to test your app. You can now see your app in multiple languages simultaneously. Great job!
xcrun simctl list | grep Demo
in the terminal. Delete any duplicate simulators and try again.
RayWonders also supports a few other languages. Run the following:
./sim_utility.sh launch Demo com.raywenderlich.RayWonders ja_Jp ja
RayWonders now launches in Japanese on a new simulator.
As a fun challenge, implement two more commands in the sim_utility script.
- Cleanup: This deletes a simulator given a simulator name.
- Help: This prints a menu of all the commands supported by the script.
You’ll find the final version of the script with all these options implemented in the Scripts folder in the downloaded materials.
Where to Go From Here?
Download the project by clicking the Download Materials button at the top or bottom of this page.
In this tutorial, you’ve learned tons of useful simulator and command-line options. To learn more, please check out these WWDC videos:
I hope you’ve enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below.
Comments