Downloadable Fonts in iOS 7

iOS 7 has significantly expanded the number of downloadable fonts available for iOS apps.

iOS 6 supported downloadable fonts. This is hinted at in Apple’s Tech Note HT5484, which says “Apps can also install the following fonts as necessary”.

The fonts available to install mostly provided support for non-English text.

With iOS 7, they’ve expanded the list of fonts to include, as of this writing, 283 fonts. The font list is dynamic, so this may change.

Some of the highlights are: Bookman Old Style, Century Gothic, Garamond, Iowan Old Style, New Peninim (can't find a good link for this one), PT Sans, and some ornamental fonts like Wingdings. And Comic Sans. Full list here.

You can explore the downloadable font list on your iPhone using my Unicode Character Viewer app in the App Store.  

Discovering Available Fonts

Discovering the fonts available for download is done through a function that’s been with us for a while, CTFontDescriptorCreateMatchingFontDescriptors.

What’s new in iOS 7 is that you can ask this function for fonts that have the kCTFontDownloadableAttribute set, and that the function may make a network call to get the font list.  This will take an indeterminate amount of time, and is synchronous, so don’t call it on your main thread.

This function will return an array of UIFontDescriptor objects, which you can enumerate to discover the fonts available for download.

Here's a code snippet that will retrieve the font list in a useful form: https://gist.github.com/fdstevex/6741638.

Downloading Fonts

Once you know what font you want, the next step is downloading it. Before downloading it, ensure that it’s not already available by simply trying to open it. If you can open it, then it’s already on the device. If not, you’ll need to download it.

The function you use to download fonts is CTFontDescriptorMatchFontDescriptorsWithProgressHandler. This function is not included in the iOS 7 documentation yet, but is mentioned in the API diffs, and is demonstrated in the DownloadFont sample that Apple provides, so this function is safe to use in App Store apps.

The progress handler you pass to this function is called at various times during the download to let you know how the download is going.  You can use this to update a progress indicator to keep the user informed of the download progress.

I've created a simple Cocoa wrapper for this function that uses a delegate to notify the application of download progress.  It's on github: FDSFontDownloader

Using in Your Apps

Having these fonts available is great, but how do we let users use them in our applications?

My application Resume Designer supports downloadable fonts on iOS 7.  (And it's a great app, so you should buy it, or gift a copy to a friend who needs a job).  I'll describe how I implemented it.

First off, the font list you get back from this API is too long to simply present to the user.  There are a lot of fonts that are specific to certain locales (and you can filter for those - Unicode Character Viewer shows the locale to the right of the downloadable font names).  What I did is go through all the available fonts, and whittle the list down to fonts that I thought might be good choices for using in a résumé.  

That 283 number includes variations like bold and italic, and generally you don't want to present these to the user separately.  The user chooses the font family, and then sets attributes like bold and italic on portions of text to choose the variants. In the end I chose small set of 13 font families to make available as downloadable fonts.

When presenting the font list, you won't have the ability to render a preview using the font itself.  A good experience here would be to include a bitmap font sample with the app so you can present it in the UI, but you should indicate that the font will require a download.

When the user selects a downloadable font that hasn't already been downloaded, you obviously need to download it.  Because this is essentially a synchronous operation from the user's perspective (although not in code), show a progress indicator while the user waits for the font download.  The fonts are small enough that this takes just a few seconds.

An important thing to remember with downloadable fonts is that they may not be on the device the next time the user opens your app.  If the user chooses a download font, exits your app, and then does a wipe/restore on their device, or buys a new device, or opens the file on a different device (if you support iCloud or some other sync mechanism), then the app will find the font is missing. You must support a fallback mechanism.

When the user opens a document that requires a font that isn't present, download the font.  The user will have to wait a few seconds to open the document, but then it will appear as they left it.

The user may be offline when opening the document, and that's when you'd use the fallback font.

The strategy I've chosen in Resume Designer is to simply use a predefined font as a fallback, inform the user that the app is using a fallback font, but leave the download font name in the document.  That way, the user can edit the document while offline (with the fallback font) but later they can open the document with a network connection and go back to using the chosen font.  Or the user can select a font that is present on the device.

Development and Troubleshooting

When you call CTFontDescriptorCreateMatchingFontDescriptors, the system will make a request for this URL:

http://mesu.apple.com/assets/com_apple_MobileAsset_Font/com_apple_MobileAsset_Font.xml

Hit that URL and you'll get an XML list of all the fonts available to download, including a lot of extra information.  Better to get the information through the API, since this format isn't documented and may change, but it's a good way to examine the font list.

In testing, you'll want to re-download a font you've already downloaded.  This is easy enough on the simulator, as the fonts are stored in your Application Support directory:

~/Application Support/iPhone Simulator/7.0/Library/Assets/com_apple_MobileAsset_Font

Delete them, restart the simulator, and you can download them again.

On an actual device, I'm not aware of any way to remove the downloaded fonts.  Letting users download fonts is going to consume space on the device, and I'm not sure if the OS ever reclaims that space.  Something to think about.

The FDSFontDownloader code on GitHub is a good place to get started.