What Is Application Sandboxing

Privacy and security have always been top priorities for Apple. Sandboxing is a result of that commitment. On iOS, applications have been sandboxed from day one. This isn't true for macOS applications. Sandboxing was added to macOS with the announcement of the Mac App Store in 2010.

But what is sandboxing? How does it impact developers? And why does the operating system sandbox applications?

Why Is Sandboxing Necessary?

Sandboxing significantly increases the security and integrity of the operating system by limiting what an application is allowed to do. On iOS, for example, an application cannot access the sandbox of another application. Why is that important?

Even though Apple reviews every application before it is allowed into the App Store, the review process isn't perfect. It is possible that malicious applications make their way into the App Store. If every third party application would be able to access the file system and the sandbox of other applications, the platform would soon be in disarray.

But an application doesn't need to be malicious for it to cause mayhem. An innocent bug could also cause havoc. By sandboxing applications, this is much less likely.

What Is Sandboxing?

For historical reasons, sandboxing rules for macOS are less strict than those for iOS, tvOS, and watchOS. The macOS operating system and its file system operate differently and are structured differently.

The idea is similar, though. Every application is given a sandbox, a directory it can use to store data in. If the application needs access to data on the device that isn't located in the application's sandbox, it needs to request the data through a system interface. And even the system interfaces have their limitations. Not everything is accessible through a system interface.

The photos library of a device is a fine example. An application doesn't have direct access to the photos stored on the user's device. To access the user's photos, third party application need to use a system interface. The idea is that the operating system knows exactly what data the application accesses if it isn't located in the application's sandbox.

System interfaces add a layer of security, but they also protect the user's privacy. Third party applications can access the user's health data through the HealthKit framework. But the user also needs to grant access to the application before it is allowed to read or write health data.

Where Is the Sandbox Located?

Even though the location of the application sandbox isn't important from a development perspective, you can ask the operating system for its location on the device. The following example targets the iOS platform.

Fire up Xcode and create a new project. In the AppDelegate class, update the application(_:didFinishLaunchingWithOptions:) method as shown below. We ask the operating system for the location of the home directory, the root of the application sandbox.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NSHomeDirectory())

    return true
}

If you run the application on a physical device, the output in the console looks something like this.

/var/mobile/Containers/Data/Application/1F1468AA-A6D4-4379-84C7-ABC99BDC9302

The output looks a bit different if you run the application in the simulator.

/Users/Bart/Library/Developer/CoreSimulator/Devices/55B96C49-D3CE-4DFC-BE39-17CC475A8396/data/Containers/Data/Application/035918FB-26F5-434C-AA58-C069427EF41C

What Does the Sandbox Look Like?

The sandbox of an application doesn't start its life as an empty container. It houses several directories and each of these directories has a clear purpose.

Update the implementation of application(_:didFinishLaunchingWithOptions:) as shown below. We ask the operating system for the contents of the home directory, the root of the application's sandbox.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if let items = try? FileManager.default.contentsOfDirectory(atPath: NSHomeDirectory()) {
        for item in items {
            print(item)
        }
    }

    return true
}

The output in the console should look something like this.

.com.apple.mobile_container_manager.metadata.plist
Documents
Library
tmp

The first item is a property list used by the operating system. The remaining items are directories that live in every application sandbox on iOS.

Even though you are free to store data wherever you like, as long as it is in the application sandbox, you need to understand the purpose of each of these directories. Apple has provided developers with a set of guidelines, which discuss the purpose of these directories and, more importantly, how the operating system treats the contents of these directories.

For example, the contents of the tmp directory are not backed up by iTunes and iCloud. As the name of the directory implies, this directory should only be used for storing temporary documents or other blobs of data.

Documents

The Documents directory is ideal for storing data that is directly related to the user. It is very similar to the Documents directory on macOS.

If your application uses a SQLite database to store the user's data, then the database files could be stored in the Documents directory.

Library

The Library directory, contains the Caches and Preferences directories. As the name implies, the Caches directory is ideal for storing cached data. This directory can be purged by the operating system when it decides it needs to free up space on the user's device. It goes without saying that this directory is not backed up by iTunes and iCloud.

The Preferences directory contains the property list of the default defaults database. What does that mean? If you store a key-value pair in the default defaults database, that key-value pair is stored in a property list in the Preferences directory.

Add the following snippet to the application(_:didFinishLaunchingWithOptions:) method and run the application.

let userDefaults = UserDefaults.standard
userDefaults.set(true, forKey: "DidLaunch")

As you can see, a property list is created and stored in the Preferences directory of the Library directory.

The property list is stored in the Preferences directory.

The user defaults are stored in a property list.

tmp

Temporary data should be stored in the tmp directory. This directory is purged from time to time to make sure it doesn't unnecessarily take up disk space on the user's device. Like the Caches directory, it isn't backed up by iTunes and iCloud.

Application Bundle

The application itself isn't located in the sandbox. This is a common misconception. To find out where the application bundle is located, you can ask the bundle of the application for its URL or path.

Bundle.main.bundleURL
Bundle.main.bundlePath

Update the implementation of the application(_:didFinishLaunchingWithOptions:) method as shown below.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NSHomeDirectory())
    print(Bundle.main.bundlePath)

    return true
}

If you run the application on a physical device, the output in the console looks like this. This illustrates that the application bundle isn't located in the application sandbox.

/var/mobile/Containers/Data/Application/6B54E61E-2F37-4203-A11D-AED2C1E6762E
/var/containers/Bundle/Application/2428465B-4D78-4C0B-B989-7290AAD27A7F/Sandboxing.app

You cannot and should not modify the contents of the application bundle. If the application bundle is modified, the operating system refuses to launch the application.

Inspecting the Sandbox

During development, it can be useful to inspect the contents of an application's sandbox. Xcode makes this very easy. Select Devices from Xcode's Window menu and, on the left, select the device the application is installed on.

Inspecting the Application Sandbox

At the bottom, select the application you are interested in and click the gear icon. You can show, replace, or download the container of the application.

Download, Show, or Replace the Application Sandbox

Application Sandbox of Samsara

If you use the simulator for development, then this is less trivial. The sandbox of an application installed on a simulator is located in the bowels of the Library directory on your development machine.

Fortunately, there is a solution. I have been using SimPholders for several years and it is an indispensable tool for Cocoa development. It gives you quick access to the applications installed on the various simulators you have access to.

SimPholders gives you easy access to the application sandbox.

SimPholders gives you easy access to the application sandbox.

What's Next?

It is important that you know what the application sandbox is and represents. The directories it contains each have a purpose and you need to be careful which directory you store data in.

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By