xcrun simctl installとxcrun simctl uninstallは、シミュレータへアプリをインストール・削除するサブコマンドである。
参考: xcrun simctl listappsでiOSシミュレータのインストール済みアプリ一覧を表示する
参考: xcrun simctl get_app_containerでiOSシミュレータのアプリのコンテナパスを取得する
基本的な使い方
install <device> <path>で.appバンドルをインストールし、uninstall <device> <bundle identifier>でアプリを削除する。
$ xcrun simctl install "TIL Install iPhone" ./TILInstallApp.app
$ xcrun simctl listapps "TIL Install iPhone" | grep -c "com.til.installtest"
2
$ xcrun simctl uninstall "TIL Install iPhone" com.til.installtest
$ xcrun simctl listapps "TIL Install iPhone" | grep -c "com.til.installtest"
0
<path>はカレントディレクトリ基準の相対パスとしても解釈される。
grep -cの結果が2件になっているのは、listappsの出力形式(NSDictionaryのdescription)では辞書のキーとCFBundleIdentifierフィールドの両方に同じbundle identifierが出現するためである。
対象デバイスは起動中(Booted)である必要がある
install・uninstallいずれも、対象デバイスが起動中でないとUnable to lookup in current state: Shutdown(code=405)でエラーになる。
appinfoやlistappsと同じ制約である。
uninstallは未インストールのアプリを指定してもエラーにならない
存在しないパスをinstallに指定すると明確なエラーになる。
$ xcrun simctl install "TIL Install iPhone" /tmp/does-not-exist.app
An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=2):
Simulator device failed to install the application.
Underlying error (domain=NSPOSIXErrorDomain, code=2):
lstat of /tmp/does-not-exist.app failed: No such file or directory
一方uninstallは未インストールのbundle identifierを指定してもエラーにならず、終了コードも0のままである。
$ xcrun simctl uninstall "TIL Install iPhone" com.til.neverinstalled
$ echo $?
0
uninstallは「対象が存在しなければ何もしない」という冪等な動作をするため、CIのクリーンアップ処理で存在確認なしに呼び出しても安全である。
既にインストール済みのbundle identifierへの再インストールはアプリデータを保持する
同じbundle identifierのアプリが既にインストールされている状態でinstallを実行すると、.app本体は新しいものに置き換わるが、Documentsなどのアプリデータは保持される。
$ xcrun simctl get_app_container "TIL Install iPhone" com.til.installtest data
.../Containers/Data/Application/491583AB-.../
$ echo "test-data" > "$(xcrun simctl get_app_container "TIL Install iPhone" com.til.installtest data)/Documents/test.txt"
$ xcrun simctl install "TIL Install iPhone" ./TILInstallApp.app
$ xcrun simctl get_app_container "TIL Install iPhone" com.til.installtest data
.../Containers/Data/Application/1BC308ED-.../
$ cat "$(xcrun simctl get_app_container "TIL Install iPhone" com.til.installtest data)/Documents/test.txt"
test-data
DataContainerのUUID自体は再インストールのたびに変わるが、中身のファイルは新しいコンテナへ引き継がれる。
CFBundleShortVersionStringを変更していない場合でも同様にデータが引き継がれる。
バージョン番号の変化は関係なく、「既にインストール済みかどうか」だけで判定されているとみられる。
古い方のDataContainerディレクトリは、データ移行後に削除される。
対照的に、uninstallしてからinstallし直した場合は新規インストール扱いになり、Documentsは空の状態から始まる。
$ xcrun simctl uninstall "TIL Install iPhone" com.til.installtest
$ xcrun simctl install "TIL Install iPhone" ./TILInstallApp.app
$ ls "$(xcrun simctl get_app_container "TIL Install iPhone" com.til.installtest data)/Documents/"
(空)
アプリの実機同様のアップデート動作(データを引き継ぐ)を再現したい場合はuninstallを挟まずにinstallし直し、まっさらな状態から検証したい場合はuninstallしてからinstallする、という使い分けができる。
