Automatically populating UIAppFonts

To use custom fonts in your iOS and/or watchOS apps, you need to:

  1. add the font files to your projects, and grant them membership in the appropriate target(s), so they get copied into the bundles;
  2. create the key UIAppFonts in your Info.plist file(s) (this key shows up as “Fonts provided by application” in Xcode’s property list editor), containing an array of strings naming those font files (not internal font names);
  3. load the fonts within your app, for example via UIFont(name:size:) (in Swift), or reference them from your storyboard(s).

(Note that in steps 1 and 2, if you are building a watch app, you need to make sure the font files are included in both your WatchKit app and your WatchKit Extension, per Apple’s docs.)

While trying out a few different fonts, I found step 2 tedious and easy to miss, especially with three targets to update. So I automated it, and wanted to record it for myself and anyone else looking.

In each target, I went to Build Phases, and added a “Run Script” step. The contents of this step are just:

Resources/update_plist_fonts.sh

Here, the Resources folder, directly within my source root, is where I put the font files as well as this script; there’s nothing special about it. The script is written using Xcode build environment variables so that it can be invoked from any target and affect the right files.

Here are the contents of update_plist_fonts.sh:

#!/bin/sh

FONTDIR="Resources"

PLIST="${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}"
PLISTBUDDY="/usr/libexec/PlistBuddy"
FONTPATH="${SOURCE_ROOT}/${FONTDIR}"

"${PLISTBUDDY}" -c "Delete :UIAppFonts" "${PLIST}"
"${PLISTBUDDY}" -c "Add :UIAppFonts array" "${PLIST}"
cd "${FONTPATH}"
for f in *.[ot]tf ; do
  "${PLISTBUDDY}" -c "Add :UIAppFonts: string \"${f}\"" "${PLIST}"
done

Here, I set FONTDIR to that same Resources folder. Change it to match your directory layout. Everything else should be project-independent. All it does is search that directory for any file named *.otf or *.ttf (the OpenType and TrueType font extensions, respectively), and use the resulting filenames to construct a new UIAppFonts array.

The script edits the Info.plist after it’s copied to the build outputs; it does not touch your (presumably source-controlled) source files, so you won’t see these changes if you open Info.plist in Xcode. (To find the output file, locate the target output under Products in the left navigation tree, right-click, view in Finder, then right-click on the bundle and view package contents; it’s in there.)

Plist editing is done using Apple’s PlistBuddy program, which comes with macOS, and has a manpage for more details; Apple has an older copy of this manpage here.