Applications on iOS and macOS are packaged differently from applications on other platform, most notably Windows.
On other platforms, the end result of compiling your project is a binary file that contains the compiled code. It’s then up to you as a developer to package that binary up with the resources it needs. On Linux, you generate a package file which can vary depending on the distribution one’s using. On Windows, it’s traditional to create an installer, which is an additional application that unpacks the binary and resources.
macOS and iOS take a different approach to application. This approach stems from the concept of a package—a folder that contains a number of items but is presented to the user as a single file. Many document formats use packages as a convenient way to store and organise their data, because storing different chunks of data as separate files means that the program doesn’t have to implement logic that unpacks a single file.
In the context of Linux, a package means something different. On Linux, package means a redistributable file used to install software. macOS also uses the word package in this way—you can generate .pkg
files that contain software, which when opened install the software onto your machine. When you upload an app to the Mac App Store, for example, you upload a package.
And just to add to the confusion, the Cocoa framework doesn’t call folders that are presented as single files “packages” but rather calls them bundles.
The structure of application differs slightly between macOS and iOS, but the fundamental philosophy of how an application is packaged remains the same.
Components
In order to function as an application on macOS or iOS, an application must have two things at a minimum:
- the compiled binary
Simply the end result of Xcode compiling all the source code and linking it together. - An information file describing the app to the system. This information is saved in a file called
Info.plist
. This file is very important—in fact, if you remove it from the application bundle, the app can’t launch. Among other things,Info.plist
contains:- The name of the application’s icon file
- What kinds of documents the application can open
- The name of the compiled binary
- The name of the interface file to load when the application start up
- What languages the application supports (such as French, English etc.)
- Whether the application supports multitasking (for iOS)
- The Mac App Store category the application is in (for macOS)
Applications also contain every resource that was compiled in—all the images, files, sounds and other items that were added to the project via Xcode. The structure of macOS and iOS application bundles are a little different.
macOS app structure
The structure of a macOS application named MyApp
looks like this:
- MyApp.app
The top-level of the package- Contents A folder that contains the application itself
- Info.plist The file that describes the application to the system
- MacOS A folder that contains the app’s compiled binary
- MyApp The app’s compiled binary
- PkgInfo A legacy file that describes the app’s maker and what the app is
- Resources A folder that contains all of the compiled-in resources
- Contents A folder that contains the application itself
iOS app structure
The structure of an iOS application named MyApp
looks like this:
- MyApp.ipa
The top-level of the package- MyApp The app’s compiled binary
- Info.plist The file that describes the application to the system
- Default.png The image that is shown while the app is launching
- Default@2x.png The double-resolution version of
Default.png
, used on high-resolution devices
- Default@3x.png The triple-resolution version
- Embedded.mobileprovision The provisioning profile that identifies the app as able to run on a device
- Entitlements.plist A file that describes what the application may or may not do
Using Bundle to find resources in Applications
Because an application could be anywhere on the system, our code can’t use absolute paths to determine the location of resources. As far as code goes, the application works the same regardless of which platform it runs on, thanks to a useful class called Bundle
.
Remember that Cocoa refers to packages (i.e. folders containing app resources) as bundles. By using a bundle object, you can access a bundle’s resources without knowing the structure of the bundle.
let resourceURL = Bundle.mainBundle()
.URLForResource("SomeFile", withExtension: "txt")
On macOS, this method looks inside the Resources
folder in the application bundle for the named file. On iOS, it looks inside the root folder of the application bundle. If you add an image or other resource to your project, it is copied into the application bundle when the project is built.
Absolute paths and URLs are functionally the same when referring to files stored on disk, but using URLs is preferred—a string could theoretically contain anything, where as a URL always points to a location. This includes file URLs, which look like this: file:///Applications/Xcode.app/
. You can therefore use URLs in any case where you’d normally use a file path.