How do you include custom fonts in your application, if they don’t reside in the main bundle? In this case, loading them through the conventional PLIST method doesn’t work, and you will need to resort to CoreGraphics to register them programmatically.

Typefaces are an essential part of good design. On iOS, custom fonts can be added to apps through a somewhat convoluted process. Chris Ching has a good write-up on the topic, but in short: ensure the font files are properly included in your app’s target and declare them in your app’s Info.plist (“Fonts provided by application”). This works well in the straightforward case where the fonts are simply embedded into the main app bundle.

You quickly run into the limits of the PLIST-based registration method when they live outside of the main bundle, e.g. in a separate .framework. In this case, simply register the fonts using the older CoreGraphics APIs.

Marco Arment described the approach on his blog back in 2012, but the example code he lists is Objective-C. Fortunately, the Swift version of this code is much less cumbersome than its Obj-C counterpart, as less C-trickery is required:

// Load bundle which hosts the font files. Bundle has various ways of locating bundles.
// This one uses the bundle's identifier
guard let bundle = Bundle(identifier: "some.framework.identifier")
else { return }

// List the fonts by name and extension, relative to the bundle
let fonts = [
    bundle.url(forResource: "gotham_book", withExtension: "ttf"),
    bundle.url(forResource: "gotham_medium", withExtension: "ttf")
]

// Iterate over the resulting urls, filtering out nil-values with .flatMap()
for url in fonts.flatMap({ $0 }) {
  // Create a CGDataPRovider and a CGFont from the URL.
  // Register the font with the system.
    if let dataProvider = CGDataProvider(url: url as CFURL) {
        let font = CGFont(dataProvider)
        CTFontManagerRegisterGraphicsFont(font, nil)
    }
}

Just make sure you don’t forget to remove any duplicate PLIST declarations, or your app will throw an exception at startup.

Update

@sveinhal in the comments suggested this functional rewrite of the above code, which is way more succinct if that’s your cup of tea:

let fonts = [
bundle.url(forResource: "gotham_book", withExtension: "ttf"),
bundle.url(forResource: "gotham_medium", withExtension: "ttf"),
]

fonts
.flatMap { $0 }
.flatMap { CGDataProvider(url: $0 as CFURL) }
.map(CGFont.init)
.forEach { CTFontManagerRegisterGraphicsFont($0, nil) }
Previous ArticleNext Article

This post has 4 Comments

4
  1. let fonts = [
    bundle.url(forResource: "gotham_book", withExtension: "ttf"),
    bundle.url(forResource: "gotham_medium", withExtension: "ttf"),
    ]

    fonts
    .flatMap { $0 }
    .flatMap { CGDataProvider(url: $0 as CFURL) }
    .map(CGFont.init)
    .forEach { CTFontManagerRegisterGraphicsFont($0, nil) }

Leave a Reply

Your email address will not be published. Required fields are marked *

A.

Android device debugging on Linux Mint: “error: insufficient permissions for device: udev requires plugdev group membership”

As I rejoiced in the achievement of finally finding a Linux distro which plays well with my Dell XPS 13 (2019 edition, model 9380), I plugged in my Moto test device, intending to continue working on an Android app. Pressing the Run button promptly made Android Studio (3.4) do its compilation magic, but got stopped in its tracks rather quickly. An angry-looking error message awaited me:

error: insufficient permissions for device: udev requires plugdev group membership

Oops, no device debugging for you.

Android Studio also left a note pointing me to their developer page on the subject. As I suspected, it seemed I had some configuration work left to get device debugging working on Linux. However, following Google’s instructions on setting up adb didn’t do much to resolve my problem. The part about adding yourself to the udev group is important, though, as it’s linked to the actual solution described in the next paragraph.

sudo usermod -aG plugdev $LOGNAME

Adds your user to the plugdev group.

Update: Someone mentioned recently that the below steps may not actually be required; just logging out and back in again at this point, should also do the trick. YMMV of course :-).

An ill-timed dog walk (let’s just say I hadn’t expected to be caught in the middle of a downpour), and a few mildly frustrated Google searches later, I ran across a blog post from 2013 (!) on the subject of “Adding udev rules for USB debugging Android devices“, by Janos Gyerik.

I will not pretend to know why this extra configuration is required, but it describes looking up the device’s identifier and adding it to the aforementioned plugdev access group, so Android Studio can properly access the USB device.

And there you go, a working USB debugging connection to my Android device, thanks to some great advice from 2013!