If you maintain an app like ConnectStats that has a lot of local files on the device and does not rely on the cloud constantly for input, each time Xcode upgrade all the iOS Simulator starts empty again and loose all the files from the previous version.
The iOS simulator keep it’s file in some complicated folder structure and the folder change each time you start it, so it can be quite tricky to locate the files. And so quite painful to locate all the folder for the previous and new version and move all the files over.
I’ll go over the solution I use in this post, using a small cli tool I wrote
Finding the Simulator Folders
In the past, I maintained Simulator Data Finder to help me easily locate these files. Since then I stopped using it because the current version of simctl
provided by Apple lets you easily find the folder for a currently running app in the simulator, with the following command applied to connectstats:
xcrun simctl get_app_container booted net.ro-z.connectstats data
It is then very easy to wrap this into a shell function to have quick access from the terminal like below
function simcd () {
cd $(xcrun simctl get_app_container booted $1 data)
}
This works great and I am now using that all the time for development instead of my old app Simulator Data Finder. But when Xcode upgrades this function does not find the previous version simulators, so I then had to revert back to Simulator Data Finder, and manually copy all the files.
Now that I was so used to simctl
and the simple wrapper simcd
I felt the need to get a better solution for moving the files from one version to the other.
Finding old simulator directories
To find apps in old simulator, I used to the same trick I had used in Simulator Data Finder by adding a small snippet to the start of the app that saves a small hidden file in the document folder that we can then search in the file system to locate the document folder of that app. A header file can be found here for objective c or here for swift. The logic is the same for both, here is the swift implementation
func RZSimNeedle() { let needlePath = NSSearchPathForDirectoriesInDomains( .DocumentDirectory, .UserDomainMask, true) let documentsDirectory = needlePath[0] as String let bundleIdentifier = NSBundle.mainBundle().bundleIdentifier if (bundleIdentifier != nil) { let needle = documentsDirectory + "/.simneedle." + NSBundle.mainBundle().bundleIdentifier! NSData().writeToFile(needle, atomically: true) } }
You can then easily write code that will locate the document directory. I wrote a python utility simctl.py that leverage this file to automate some workflow around upgrade of the simulator.
Moving files from old to new Simulator
You can find the utility simctl.py
along my other quick tools here. Beside a few help command to find information and details about existing simulator and apps container. The core command to run to upgrade app containers to new version is
simctl.py upgrade
This will print a report for all the app and simulator version it finds along with the command to run to mv all the file from one version to the other. The output will look like this
iPhone 11 Pro Max has app to upgrade net.ro-z.connectstats: iOS 13.3[Feb 2020: 4] iOS 13.4[Apr 2020: 5] iPhone SE (2nd generation) has app to upgrade net.ro-z.connectstats: iOS 13.5[Jul 2020: 5] iOS 14.0[Jul 2020: 5] iPad Pro (11-inch) (2nd generation) has app to upgrade net.ro-z.connectstats: iOS 13.4[May 2020: 57] *iOS 14.0[Oct 2020: 1] >iOS 14.2[Nov 2020: 324] Command to execute: find /Users/brice/Library/Developer/CoreSimulator/Devices/0C6A55F6-61DC-40C7-852D-AD6C019640C1/data/Containers/Data/Application/D6530424-1CBE-4508-8C5B-7237CFD19DBE/Documents -type f -not -name '.*' | xargs -J % mv -f % /Users/brice/Library/Developer/CoreSimulator/Devices/F8B1FE98-E43C-4CA6-A98C-9616BF51889B/data/Containers/Data/Application/74192656-4549-4040-A1EB-B7B1A31BE632/Documents
Here it tells you for example that the simulator iPad Pro has the app net.ro-z.connectstats
from version iOS 14.0 and iOS 14.2. It also prints a find command that will move all the file from the simulator iOS 14.0 (with a *) to the simulator iOS 14.2 (with a > ). It is easy to then cut and paste that function to execute the move. I currently didn’t get the utility to execute the command as I like to double check it before executing.
Note that if you want to just find the path for a specific simulator, you can add an option simctl.py -n 'iPhone 11 Pro' upgrade -p
to display the path of the app container as here
brice:~% simctl.py -n 'iPhone 11 Pro' upgrade -p iPhone 11 Pro has app to upgrade net.ro-z.connectstats: iOS 13.3[Mar 2020: 3509] : /Users/brice/Library/Developer/CoreSimulator/Devices/5117E302-E132-43EC-9C18-83EF28B1D029/data/Containers/Data/Application/2126D354-8AFC-4C17-90A7-DD7B6D4D69FC iOS 13.4[May 2020: 2] : /Users/brice/Library/Developer/CoreSimulator/Devices/25BE4F59-CF7D-4516-A031-A0694FC11C72/data/Containers/Data/Application/19AF12E0-1302-4B83-88EA-D9387E676DC3 iOS 13.5[Jul 2020: 5926] : /Users/brice/Library/Developer/CoreSimulator/Devices/CC981917-2002-4715-86F5-209F4F9B6493/data/Containers/Data/Application/6C246894-32BF-4869-A0B5-490E9A64E4A9 iOS 13.6[Aug 2020: 5] : /Users/brice/Library/Developer/CoreSimulator/Devices/7E8C7ABF-C559-4EC3-82A1-89BD3BAF246A/data/Containers/Data/Application/69BEA9CA-B99A-4B33-A92C-887B698EA98C iOS 13.7[Sep 2020: 4] : /Users/brice/Library/Developer/CoreSimulator/Devices/30728C75-BC74-4FC7-A803-B30646F5889C/data/Containers/Data/Application/183AAF2C-C54B-46B7-9C9D-3662EA20827C *iOS 14.0[Oct 2020: 2] : /Users/brice/Library/Developer/CoreSimulator/Devices/C4549DAA-79A7-4107-BEBD-27EDFED6C40D/data/Containers/Data/Application/CE8656FE-46F5-46BD-AD1B-65D433ACCBAD >iOS 14.2[Dec 2020: 7371] : /Users/brice/Library/Developer/CoreSimulator/Devices/10C3C9FA-C357-4251-B58D-F7149D30EB78/data/Containers/Data/Application/F24D35E3-8A76-43E9-BB6D-F4A7935D8CC2 Command to execute: find /Users/brice/Library/Developer/CoreSimulator/Devices/C4549DAA-79A7-4107-BEBD-27EDFED6C40D/data/Containers/Data/Application/CE8656FE-46F5-46BD-AD1B-65D433ACCBAD/Documents -type f -not -name '.*' | xargs -J % mv -f % /Users/brice/Library/Developer/CoreSimulator/Devices/10C3C9FA-C357-4251-B58D-F7149D30EB78/data/Containers/Data/Application/F24D35E3-8A76-43E9-BB6D-F4A7935D8CC2/Documents net.ro-z.connectstatstestapp: iOS 13.3[Feb 2020: 199] : /Users/brice/Library/Developer/CoreSimulator/Devices/5117E302-E132-43EC-9C18-83EF28B1D029/data/Containers/Data/Application/4B1CFBF8-C82B-42D6-B420-D17A1382C492 iOS 13.4[May 2020: 198] : /Users/brice/Library/Developer/CoreSimulator/Devices/25BE4F59-CF7D-4516-A031-A0694FC11C72/data/Containers/Data/Application/7765598A-3417-4315-B749-F8D7AAC0C220 iOS 13.5[Jun 2020: 14] : /Users/brice/Library/Developer/CoreSimulator/Devices/CC981917-2002-4715-86F5-209F4F9B6493/data/Containers/Data/Application/80983338-3E3B-4D9C-8072-74B4CBBC5E57 iOS 14.0[Sep 2020: 241] : /Users/brice/Library/Developer/CoreSimulator/Devices/C4549DAA-79A7-4107-BEBD-27EDFED6C40D/data/Containers/Data/Application/CA3D2E8B-7738-4CC2-BFE1-0E73FF1D2FB7 *iOS 14.1[Nov 2020: 12] : /Users/brice/Library/Developer/CoreSimulator/Devices/DCCC22C0-68B7-4D79-82DB-190156234AD1/data/Containers/Data/Application/3CD5597B-C014-4318-9D4C-B31D54840B7A >iOS 14.2[Dec 2020: 20] : /Users/brice/Library/Developer/CoreSimulator/Devices/10C3C9FA-C357-4251-B58D-F7149D30EB78/data/Containers/Data/Application/BC797B48-ECEA-4572-837E-B2607313B4B5 Command to execute: find /Users/brice/Library/Developer/CoreSimulator/Devices/DCCC22C0-68B7-4D79-82DB-190156234AD1/data/Containers/Data/Application/3CD5597B-C014-4318-9D4C-B31D54840B7A/Documents -type f -not -name '.*' | xargs -J % mv -f % /Users/brice/Library/Developer/CoreSimulator/Devices/10C3C9FA-C357-4251-B58D-F7149D30EB78/data/Containers/Data/Application/BC797B48-ECEA-4572-837E-B2607313B4B5/Documents
this is quite a specialised tool, but it’s very useful to me. I hope it will help or give ideas to other to help with their workflow with the iOS simulator