Codementor Events

XCode App Data

Published Mar 08, 2019
XCode App Data

Not many iOS developers know about XCode App Data bundles.

Shiny new feature

Imagine you developing a feature deep into app functions. For a user to get to that feature they might need to sign up for the service, login, pass the onboarding, create some content and then they will see your shiny feature. Let's say you want to congratulate the user with fireworks. The challange is how you test that feature or even see how it works, as you need to walk all that path to get to it.

Getting to it

Another case might be when user reported a bug and you are trying to reproduce it. Do you start over by creating account and content and navigating to get to the place of failure? And even if you do all that work of recreating the state where user experienced the problem, how you make it repeatable?

XCode App Data

XCode App Data is a bundle containing complete state of the app. It has .xcappdata extension. You can load that bundle into app and get immediately into that state of a feature or a bug you want to explore.

Start app with state

XCode has an option to start the app with a given Application Data package.
Edit the scheme you use to launch the app (Shift-Command-<) then select Run action and Options tab:
Screen Shot 2019-03-07 at 8.40.45 PM.png
In the Application Data drop down menu you can select one .xcappdata bundle from your project to use.

Create App Data bundle

One of the fasterst way to create XCode App Data package is to download app container from your test device.
DownloadContainer.png
Open Devices and Simulator in XCode (Shift-Command-2) select your app in the list of installed apps, then click in the gear icon to show container menu. Save the downloaded container to your XCode project. Obviously you do not need to inlcude it into any target.

Test Setup Automation

You can also load the XCode App Data bundle for your UI Tests and even Application Tests. I often have several .xcappdata bundles in a project to represent different states of the app.

The Bug

Current version of XCode has a bug not loading XCode App Data container even it is selected in Options. Please report this to Apple to upvote it: Open Radar - Cannot use xcappdata package in simulator

To workaround that bug I've created loadAppData() function that does just that depending on environment variable passed at launch.

import Foundation

func loadAppData() {
    let processInfo = ProcessInfo.processInfo
    guard let appDataPath = processInfo.environment["LOAD_APPDATA"] else {
        return
    }
    let loaderUrl = URL(fileURLWithPath: #file)
    let bundleUrl = URL(fileURLWithPath: appDataPath, relativeTo: loaderUrl).appendingPathExtension("xcappdata")
    let contentsURL = bundleUrl.appendingPathComponent("AppData")
    let fileManager = FileManager.default
    let enumerator = fileManager.enumerator(at: contentsURL,
                                            includingPropertiesForKeys: [.isDirectoryKey],
                                            options: [],
                                            errorHandler: nil)!
    let destinationRoot = fileManager.urls(for: .libraryDirectory, in: .userDomainMask).last!.deletingLastPathComponent()
    try! fileManager.removeItem(at: destinationRoot)
    let sourceRoot = contentsURL.standardizedFileURL.path
    while let sourceUrl = enumerator.nextObject() as? URL {
        guard let resourceValues = try? sourceUrl.resourceValues(forKeys: [.isDirectoryKey]),
            let isDirectory = resourceValues.isDirectory,
            !isDirectory else {
                continue
        }
        let path = sourceUrl.standardizedFileURL.path.replacingOccurrences(of: sourceRoot, with: "")
        let destinationURL = destinationRoot.appendingPathComponent(path)
        try! fileManager.createDirectory(at: destinationURL.deletingLastPathComponent(),
                                         withIntermediateDirectories: true,
                                         attributes: nil)
        try! fileManager.copyItem(at: sourceUrl,
                                  to: destinationURL)
    }
}

The above function is safe to include into the app target, as it only does container replacement when your pass LOAD_APPDATA environment.

Complete example

You can find complete example with an automated UI test on GitHub here: https://github.com/paulz/WeightTracker

The example project has Continuous Intergration on Travis passing all tests here: https://travis-ci.org/paulz/WeightTracker

The code is also 100% test covered by testing both states with and without .xcappdata: https://codecov.io/gh/paulz/WeightTracker/tree/master/WeightTracker

Discover and read more posts from Paul Zabelin
get started