Loading iOS fonts dynamically
I recently mentioned on the podcast that some of Instapaper’s font licenses require me to encrypt the font data, so I need to decrypt and load them dynamically instead of the usual method of putting unencrypted OTF filenames in the UIAppFonts
key in Info.plist
. Well, it Turns Out™ that almost noboody knows you can do this. I didn’t, either, until a programmer from one of the font foundries told me about CTFontManagerRegisterGraphicsFont
.
Here’s a usage example:
NSData *inData = /* your decrypted font-file data */;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error)
NSLog(@"Failed to load font: %@", errorDescription);
CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
You can load a font this way at any time during your app’s execution, and it immediately becomes available in UIFont
and UIWebView
(via regular font-family
CSS declarations, no @font-face
required) just as if it had been declared in UIAppFonts
.
How you encrypt the font data in the bundle is up to you, but since you may need to decrypt hundreds of kilobytes of font data, you should choose a method with fast decryption.
Also, be careful what you agree to in your licensing contracts. Like any other method of app-resource encryption and obfuscation, you can’t guarantee that nobody will ever be able to copy the unencrypted data out. You can only make it harder, make it take much more effort, and reduce the number of people who can do it.