Anatomy of an App Bundle
I recently needed to use CMake to generate macOS app bundles, and I had a really hard time getting the icon to work (macOS 10.14). No matter what I did, the icon just would not show up, although strangely, it did work on my old 10.10 laptop. This led me to a journey into the macOS bundle.
AppName.app/ | App bundle directory | ||||||
Contents/ | |||||||
Info.plist | See below | ||||||
PkgInfo | Obsolete; only used by Carbon | ||||||
Resources/ | |||||||
AppIcon.icns | App icon for 10.12 and before | ||||||
Assets.car | All icons (including app icon) 10.13 and later | ||||||
image.png | |||||||
en.lproj/ | Localizations | ||||||
InfoPlist.strings | |||||||
Localizable.strings | |||||||
jp.lproj/ | |||||||
InfoPlist.strings | |||||||
Localizable.strings | |||||||
Frameworks/ | Any shared libraries included in the bundle | ||||||
libdependency.dylib | |||||||
MacOS/ | Executables | ||||||
AppName | Main executable | ||||||
external_tool | Helper executable |
Required app/document icon sizes
512x512 (1x and 2x) | App Store, Finder in icon view | |
256x256 (1x and 2x) | Finder | |
128x128 (1x and 2x) | Finder, Dock | |
32x32 (1x and 2x) | Finder list views | |
16x16 (1x and 2x) | Spotlight |
The Info.plist is something like the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!— Boilerplate -->
<key>CFBundleInfoDictionaryVersion</key> <!— always 6.0 -->
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<!— Name of bundle. Used if CFBundleDisplayName does not exist.
Should be 16 characters or less -->
<key>CFBundleName</key>
<string>AppName</string>
<!— Name of executable file (in case the user renames the bundle) -->
<key>CFBundleExecutable</key>
<string>AppName</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<!— Obsolete (macOS 10.12-). Name of the .icns file containing the
app icon, located in the Resources/ directory. The “.icns” extension
is not necessary. By default this value is “AppIcon”. -->
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<!— macOS 10.13+: name of the icon in the Resources/Assets.car file.
If this key exists but the Resources/Assets.car file does not exist,
the CFBundleIconFile (usually AppIcon.icns) will NOT be used and
you will get the default application icon. -->
<key>CFBundleIconName</key>
<string>AppName</string>
<key>CFBundleIdentifier</key>
<string>com.geoffprewett.AppName</string>
<!— Version keys -->
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleLongVersionString</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<!— Optional; displayed in Finder’s Get Info command -->
<key>NSHumanReadableCopyright</key>
<string>Copyright (C) 2020 by Geoff Prewett</string>
<!— Optional; sets the default language -->
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<!— Optional; sets the content types that this application can handle -->
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFile</key>
<string>documentIcon</string> <!— .icns file -->
<key>CFBundleTypeName</key>
<string>Comma-separated values</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.comma-separated-values-text</string>
</array>
<key>LSHandlerRank</key>
<string>Owner</string>
</dict>
</array>
<!— Optional; describes existing content types (not defined by this
application. (The system already knows about CSV files, but this
is an example of what its definition might look like.) -->
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>public.comma-separated-values-text</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>Comma-separated values</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>csv</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/csv</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
Helpful information:
- Icon sizes and guidelines
- Bundle documentation
- Basic keys (CFBundle*)
- Cocoa bundle keys (NS*, etc.)
- The system knows about a lot more data types than you might think. Do /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -dump to list out all the details and grep for your file type.