Xcode
iOS
Swift
swift4
Xcode9

iPhoneシミュレーターで動かしたアプリが出力したファイルをmacOSで開く

はじめに

実行環境はmacOS High Sierra (10.13.3)、Xcode 9.2 (9C40b)です。

SwiftでiOSアプリを作るApple公式のチュートリアルをやっていて、アプリがmealsというファイルにデータを入出力するコードが出てきました。
シミュレータ上でこのアプリを動かしたときに、ふと疑問がわいたのです。
「このmealsファイルをmacOSから直接のぞくことはできないだろうか」と。

チュートリアルでは標準ライブラリのNSKeyedArchiverでオブジェクトをシリアライズしてファイルに書き込んでいます。
が、これがSQLite.swiftのようなSQLiteラッパーを使ってファイルに書き込むようになったらどうでしょう。
そのファイルをmacOS上のDB Browser for SQLiteで確認したくなることは間違いありません。

と、いうわけで、Stack Overflowのこのやりとりを参考に調べてみたので備忘的にメモっておきます。
Is there any way to see the file system on the iOS simulator?

iOSシミュレータのディレクトリ(Xcode 9.2)

各iOSシミュレータのファイルは以下のディレクトリに配置されています。

~/Library/Developer/CoreSimulator/Devices

lsコマンドで見てみましょう。

$ pwd
/Users/<ユーザ名>/Library/Developer/CoreSimulator/Devices
$ ls
02AE7C26-627E-4DD5-997F-8C17449FB89B    2BA54912-6280-4DCC-B617-69FD59095EC4    8767140F-31D4-4D02-8A6F-A1BD57277347    C517CC4D-7C16-4C0B-A077-68088C09B8B6
151D1CFA-EAF0-4EF0-A3AE-E679C5640108    323124FB-96CA-4212-AFE6-ECA8DC7636FE    8A12F5C2-F4EA-4EB9-94E4-BF16C22EC013    C6ABCE36-8D1D-4A6E-805A-78997759A4C2
15A1E20D-0009-40CA-ADBD-816820B38E6C    3567DAA2-B426-47B0-A5D1-7B20B88D309C    8B3553F3-A219-4790-BB5E-28C284741E7F    D12F2119-0DEF-4292-BB63-B28E225396EF
15CA514C-58DB-46FC-B4B8-678ED7AE30D5    3FE92A72-4D7B-4047-A410-626D3D799600    8CEE1059-DD19-490B-AE48-8512875D388C    DD056CC5-3857-41EA-BBBD-D48AA3274502
16F49F71-CF88-4DFA-B3AF-E01240CCA406    3FEAD4E3-22A8-4A9B-AEBD-F4D8AA5FEDA1    980FA015-ACEF-4AE9-8C94-CA0B723B815E    DF1584FA-D5E1-4606-A76F-092E28469BC6
1E32ACBD-1F19-482B-AE4E-F60836FDA0E0    4BE94664-0EDA-4F38-8668-78B50B357059    9D9455E1-7363-4AD2-B724-2CF5D6D7C020    E787E0AD-916A-4B14-8A6F-FE668D72A214
1E4E92D1-CE64-482B-AF94-AE2DD41A124D    5675085F-9862-4A96-AAC9-1BEDB694E24B    A01EC8B8-F6C6-496D-86D7-BDD8BD5790F0    F7B428F3-E1E1-4D02-9658-92B9F8642F7F
2191D5B1-480C-4E19-9222-DF7C3E67BFA6    76811558-A524-4265-B6BC-616254BCDFB7    A7B4B4AE-3BC2-4AF2-88C8-A04FBE3C1960    F9607C80-6C79-4909-98E7-78164DC1C898
21B70526-175B-4305-9F32-A07644B4F44C    7740D85E-E86B-4B74-89A3-F88815DFCF81    AC508541-4E92-47EF-A2BB-6B39797BE91E    FC40A816-6049-446A-A6A2-64820FD8C969
27E26E30-B934-4495-90BF-A325E083DE9A    7B5F54E7-A1A2-418D-A7DE-4FFB98229EC5    B13584B6-EA8D-459C-A41E-82A544F918B0    FF77A96E-FB5F-4A50-A93B-9C55F71F116A
2953E794-8BA3-4358-A035-FFBB5F014C65    7CA53664-45EC-4D12-B985-B78C8B03D62E    B16FE335-31D4-4099-9864-9A08E8BA2EE4    device_set.plist
2AEF4BC3-B4B5-4568-B80D-D6E2218117FF    7D409B17-6D0F-4058-BE48-F5E736EDA0D1    C1DB0F87-F47E-4E14-ABA8-F85C1E8FE942

GUIDと思わしき名前のディレクトリがずらーっとあります。
このままだとわけがわかりません。

このディレクトリのdevice_set.plistファイルがxmlになっていて、以下のように、iOSバージョンごとに、シミュレータのデバイスとディレクトリ名の対応づけがされています。

    <!-- 前略 ... -->

    <key>com.apple.CoreSimulator.SimRuntime.iOS-11-2</key>
    <dict>
        <key>com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-</key>
        <string>980FA015-ACEF-4AE9-8C94-CA0B723B815E</string>

        <!-- 途中省略 ... -->

        <key>com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus</key>
        <string>3FE92A72-4D7B-4047-A410-626D3D799600</string>
    </dict>

    <!-- 後略 ... -->

今回、チュートリアルのFoodTrackerアプリを動かしたのはiOS11.2のiPhone-8-Plusのシミュレータだったので、3FE92A72-4D7B-4047-A410-626D3D799600ディレクトリ以下を探せば良いことになります。

アプリの実行ファイルのありか

で、このディレクトリ以下をいろいろ漁ってみたのですが、アプリケーションの実行ファイル自体は以下のディレクトリにあるようです。

~/Library/Developer/CoreSimulator/Devices/3FE92A72-4D7B-4047-A410-626D3D799600/data/Containers/Bundle/Application

つまり、一般化して書くと

~/Library/Developer/CoreSimulator/Devices/<シミュレータのGUID>/data/Containers/Bundle/Application

です。

このディレクトリ以下に、アプリごとのディレクトリが切られているわけですが、これもシミュレータと同様、ディレクトリ名がGUIDです。
そのGUIDのディレクトリ下に、アプリ名.appが見つかりました。チュートリアルではFoodTrackerという名前のアプリを作っていたので、FoodTracker.appというファイルが見つかりました。

$ pwd
/Users/<ユーザ名>/Library/Developer/CoreSimulator/Devices/3FE92A72-4D7B-4047-A410-626D3D799600/data/Containers/Bundle/Application
$ ls
3153817A-D8FD-4634-AB35-DA35E6292F04    43328334-CA84-488E-BAF8-C76D9D44B979    56A57B07-F67C-4406-9F5C-1541B53654C3    CF518D8C-DEC0-4220-8CD0-4FACF0D03806
$ cd 56A57B07-F67C-4406-9F5C-1541B53654C3/
$ ls
BundleMetadata.plist    FoodTracker.app

アプリが出力するファイルのありか

チュートリアルでは、以下のようなコードでmelasファイルの出力先を決めています。
定数ArchiveURLpathプロパティによって得られるパスに対して入出力を行なっています。

static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("meals")

このmealsファイルのありかは以下でした。findコマンドとgrepコマンドを組み合わせて力技で見つけました。

$ pwd
/Users/<ユーザ名>/Library/Developer/CoreSimulator/Devices/3FE92A72-4D7B-4047-A410-626D3D799600/data/Containers
$ find . | grep meals
./Data/Application/7E408B2A-DB42-4997-B10D-9DBA3357EB79/Documents/meals

つまり、urls(for: .documentDirectory, in: .userDomainMask)で得られるパスは

~/Library/Developer/CoreSimulator/Devices/3FE92A72-4D7B-4047-A410-626D3D799600/data/Containers/Data/Application/7E408B2A-DB42-4997-B10D-9DBA3357EB79/Documents

と対応していました。Data/Application/以下のGUID様の文字列7E408B2A-DB42-4997-B10D-9DBA3357EB79は、先述の.appファイルが格納されていたディレクトリ名とは関係がないようです。

まとめ

以上の調査から、iOSシミュレータで動かしたアプリが出力したファイルをmacOS上で閲覧するときには

  1. ~/Library/Developer/CoreSimulator/Devices/device_set.plist の中を見て、使用したシミュレータに対応するGUIDを特定する。
  2. ~/Library/Developer/CoreSimulator/Devices/<シミュレータのGUID>/ディレクトリ以下で、閲覧したいファイル名をfind . | grep <ファイル名>で検索をかける。

とするのが手っ取り早そうです。