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

# はじめに

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

[SwiftでiOSアプリを作るApple公式のチュートリアル](https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html)をやっていて、アプリが`meals`というファイルにデータを入出力するコードが出てきました。
シミュレータ上でこのアプリを動かしたときに、ふと疑問がわいたのです。
「このmealsファイルをmacOSから直接のぞくことはできないだろうか」と。

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

と、いうわけで、Stack Overflowのこのやりとりを参考に調べてみたので備忘的にメモっておきます。
[Is there any way to see the file system on the iOS simulator?](https://stackoverflow.com/questions/6480607/is-there-any-way-to-see-the-file-system-on-the-ios-simulator)

# iOSシミュレータのディレクトリ（Xcode 9.2）

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

```sh
~/Library/Developer/CoreSimulator/Devices
```

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

```sh
$ 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バージョンごとに、シミュレータのデバイスとディレクトリ名の対応づけがされています。

```xml
	<!-- 前略 ... -->

	<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`ディレクトリ以下を探せば良いことになります。

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

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

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

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

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

です。

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

```sh
$ 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`ファイルの出力先を決めています。
定数`ArchiveURL`の`path`プロパティによって得られるパスに対して入出力を行なっています。

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

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

```sh
$ 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)`で得られるパスは

```sh
~/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を特定する。
1. `~/Library/Developer/CoreSimulator/Devices/<シミュレータのGUID>/`ディレクトリ以下で、閲覧したいファイル名を`find . | grep <ファイル名>`で検索をかける。

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