In our iOS app we utilize a shared container to share files between our main iOS app and its extension (specifically WatchKit Extension), using [NSFileManager containerURLForSecurityApplicationGroupIdentifier:]
method. For debugging purposes we need to access the content of this shared container, so we've tried to export the whole App container using the Devices window in Xcode:
But, the Shared storage is not included in the container, probably because it sits in a different path on the Device itself.
The question is how can we get the shared container, if this is even possible?
I've been told by Xcode team members at WWDC that this is not possible (at time of writing, Xcode 7.3 & 8 beta 1). I've filed a radar, which I recommend everyone dupe or comment on so we can get this functionality.
Workaround for actual device -
I generally pause the execution of my app and then run following command in lldb debugger to copy the desired file from shared container to my sandbox container and then I download the container from Xcode.
po [[NSFileManager defaultManager] copyItemAtPath:[[[NSFileManager
defaultManager]
containerURLForSecurityApplicationGroupIdentifier:GROUP_NAME]
URLByAppendingPathComponent:FILE_NAME].path toPath:[[[[[NSFileManager
defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject]
URLByAppendingPathComponent:FILE_NAME] path] error:nil]
Above might look complex but if you break the above, we are doing 3 things -
Get shared container file
[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:GROUP_NAME] URLByAppendingPathComponent:FILE_NAME].path
Get sandbox document directory path:
[[[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:FILE_NAME] path]
Copy file from Shared container to sandbox
[[NSFileManager defaultManager] copyItemAtPath:SHARED_PATH toPath:SANDBOX_PATH error:nil]
I'm using this code to print out in the console the path to my local SQLite database:
NSString *groupContainer = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.myapp.mycontainer"] path];
NSString *sqlitePath = [NSString stringWithFormat:@"%@/Database.sqlite", groupContainer];
NSURL *url = [NSURL fileURLWithPath:sqlitePath];
I then copy and paste the string in the Finder -> Go to so I go directly to the folder. This works fine in the Simulator but I don't think you're able to access the your iPhone's shared container group from your Mac.
Copy your data from the group container to document directory. Then download the app container using xcode.
NSFileManager.defaultManager().copyItemAtURL(url, toURL: NSURL.fileURLWithPath(AppDelegate.applicationUserDirectory()))
url here can be obtained using below function of NSFileManager
func containerURL(forSecurityApplicationGroupIdentifier groupIdentifier: String) -> URL?
The best solution I've found is creating a backup of your device and then using iExplorer to explore the backup. There are bunch of AppDomainGroup-*
folders. Though for some reason not all of the files there are backed up (probably because of applied settings to files to be ignored during backup).
For Swift 4 - 5 add this to applicationDidEnterBackground(_ application: UIApplication)
var appGroupIdentifier = "XXXXXXX"
let fromURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
let docURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let toURL = docURL.appendingPathComponent(appGroupIdentifier)
try? FileManager.default.removeItem(at: toURL)
try? FileManager.default.copyItem(at: fromURL, to: toURL)
Then download the app container using xcode.