Psellos
Contemporary Development With Functional Programming

Run iOS Simulator from the Command Line

May 5, 2012

This note shows how to install an app in the iOS Simulator from the command line using a simple shell script. The script then starts up the simulator, and you can start your app by clicking its icon.

Note: I wrote an improved version of this script, now described on its own page: Run iOS Simulator from the Command Line.

Lion desktop with Gamut example app in iOS Simulator

While testing OCamlXSim this week I found that the command-line method I’ve been using to run iOS Simulator apps does not work well under Lion. The apps themselves work perfectly, but their Cocoa Touch interactions are freakishly slow, and the console is flooded with error messages from the simulator. It seems that some supporting parts of the simulated environment are not initialized properly when using my old method under Lion.

Things work much better if you install your iOS app as a package in the simulator’s file system, and then start the simulator as an ordinary Mac application. Here is a script that does this:

#!/bin/sh
#
# runsim   Run an app in the iOS Simulator
#
# Copyright (c) 2012 Psellos   http://psellos.com/
# Licensed under the MIT License:
#     http://www.opensource.org/licenses/mit-license.php
#
USAGE='usage:  runsim  executable  [ nibfile ]'

case $# in
1) NIBFILE="$1" ;;
2) NIBFILE="$(basename $2 .nib)" ;;
*) echo "$USAGE" >&2; exit 1;
esac

# Pick a uuid for the app (or reuse existing one).
if ! [ -f runsim.uuid ]; then
    uuidgen > runsim.uuid
fi
UUID=$(cat runsim.uuid)

TOPDIR="$HOME/Library/Application Support/\
iPhone Simulator/5.1/Applications/$UUID/"
mkdir -p "$TOPDIR"
mkdir -p "$TOPDIR/Documents"
mkdir -p "$TOPDIR/Library"
mkdir -p "$TOPDIR/tmp"
mkdir -p "$TOPDIR/$1.app"

cp $1 "$TOPDIR/$1.app"
cp "$NIBFILE.nib" "$TOPDIR/$1.app"

if [ -f Info.plist ]; then
    cp Info.plist "$TOPDIR/$1.app"
else
    cat > "$TOPDIR/$1.app/Info.plist" <<HERE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"\
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleDisplayName</key>
        <string>$1</string>
        <key>CFBundleExecutable</key>
        <string>$1</string>
        <key>CFBundleIconFile</key>
        <string></string>
        <key>CFBundleIdentifier</key>
        <string>com.example.$1</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleName</key>
        <string>$1</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleShortVersionString</key>
        <string>1.0</string>
        <key>CFBundleVersion</key>
        <string>1.0.0</string>
        <key>UIStatusBarStyle</key>
        <string>UIStatusBarStyleBlackOpaque</string>
        <key>LSRequiresIPhoneOS</key>
        <true/>
        <key>NSMainNibFile</key>
        <string>$NIBFILE</string>
</dict>
</plist>
HERE
fi

echo -n 'AAPL????' > "$TOPDIR/$1.app/PkgInfo"

if [ -f Icon.png ]; then
    cp Icon.png "$TOPDIR/$1.app"
fi
if [ -f Default.png ]; then
    cp Default.png "$TOPDIR/$1.app"
fi

# Get location of Xcode, otherwise use default
if [ -f runsim.xcloc ]; then
    XCLOC="$(cat runsim.xcloc)"
else
    XCLOC=/Applications/Xcode.app
fi

open "$XCLOC"/Contents/\
Developer/Platforms/iPhoneSimulator.platform/\
Developer/Applications/iPhone\ Simulator.app

(You can also download the latest version of runsim from Psellos.com. If you do, be sure to read the new Run iOS Simulator from the Command Line page. The latest version does more, and so is a little more complicated.)

Copy and paste these lines into a file named runsim and mark it as a script with chmod:

$ chmod +x runsim

To use the script, specify the name of your executable:

$ runsim Gamut

The script assumes your main nibfile is named the same as the executable with a .nib suffix. If this isn’t the case, you can supply the nibfile as the second parameter:

$ runsim Gamut Gamnib.nib

The iOS Simulator will launch, and your app will be on the second screen. You start your app in the simulator as you would on the real device—by touching its icon.

If the app doesn’t appear on the second screen, you may need to change the simulated version of iOS. runsim places apps into the iOS 5.1 simulator. Change the version to 5.1 in the Hardware -> Version menu of the iOS Simulator.

Be aware that the script copies files into the simulator’s space in your home directory. You’ll find them in Library/Application Support under iPhone Simulator/5.1/Applications. You may want to clear them out periodically, though they shouldn’t do much harm.

Also be aware that this approach is just as unsupported as the old one was. I can’t promise that it will work for you, but it works very well for me.

If your Xcode is installed in a non-standard place (not in the /Applications folder), create a file named runsim.xcloc with the full path of Xcode.app.

To make other changes, you’ll need to edit the script. One thing that might need changing is the version number of the simulator that you want to run—as given, the script installs apps in the iOS 5.1 Simulator. The script copies some associated images (Icon.png and Default.png) if they are present in the current directory. If your app is more complex than the OCamlXSim example apps, you will probably need to copy more contents into the application package (images, additional nibfiles, etc.).

This method of running apps in the simulator is far superior to the old one, and I was planning to switch over even if the old method was still working. The new method lets you go through all the different ways of starting, stopping, and restarting the app, and lets you test the way the app interacts with others. In our Schnapsen app, for example, I can transfer to the simulated Mobile Safari and browse through the contents of this site (Psellos.com).

I got help on this approach from my OCaml-on-iOS colleagues at Sakhalin. You can basically figure out everything by just looking at the file structure that Xcode creates for you, and doing some guessing. But it’s always great to have help with the guessing. Many thanks to Sakhalin.

Posted by: Jeffrey

Comments

blog comments powered by Disqus