5

I am creating a framework for iOS apps. It will contain some Label, Button, Lists, ... all as SwiftUI views, but in a special design. In the framework I've added a SwiftUI view called "ContentView" it has just the purpose of (visually) testing the UI-Elements in the canvas, later the ContentView will be deleted. I wanted to a add a custom font for the label design, I know how to do this:

  1. add the *.ttf file to the project
  2. adapt the info.plist "Fonts provided by app"
  3. made sure, it is listed in "Build phases" (copy bundle resources)
  4. use it with ".font(.custom("My-Font-Name", size: 34))"

But the custom font (that I already tried successfully in an other project, iOS application) is not shown in my ContentView. There is no compile error or any warning, the framework can be built and the ContentView is nicely rendered in the canvas. Only with the wrong font.

I tried restart Xcode, remove and add several times the font, but it didn't work. So here my questions:

  1. Is it possible to use a custom font within a custom framework ?
  2. As the custom font (*.ttf) is kind of an asset, has it to be treated different as part of a framework?
  3. If so, is there anything else to do (besides step 1 to 4 above mentioned) ?

Thanks for helping.

LukeSideWalker
  • 7,399
  • 2
  • 37
  • 45

2 Answers2

10

Tricky little problem, but here's what worked for me:

In the custom framework, I created a FontLoader class:

public class FontLoader {
    static public func loadFont() {
        if let fontUrl = Bundle(for: FontLoader.self).url(forResource: "Opus", withExtension: "otf"),
           let dataProvider = CGDataProvider(url: fontUrl as CFURL),
           let newFont = CGFont(dataProvider) {
            var error: Unmanaged<CFError>?
            if !CTFontManagerRegisterGraphicsFont(newFont, &error)
                {
                    print("Error loading Font!")
            } else {
                print("Loaded font")
            }
        } else {
            assertionFailure("Error loading font")
        }
    }
}

Then, in my AppDelegate's didFinishLaunchingWithOptions, I made sure to import my framework and load the font:

import FontTestFramework
//...
FontLoader.loadFont()

Later, in my view, I used the font successfully with:

Text("Test")
  .font(.custom("Opus", size: 30))

I tested to make sure that it wasn't just loading the version installed on my Mac (since I was using the simulator) but commenting out the FontLoader.loadFont() call, and sure enough, it defaulted back to San Francisco

I tried this with an otf file, but I don't think there's any reason ttf should behave differently. Obviously, the otf file had to be part of the framework's target.

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Wow, man, thanks for your answer. I wonder how much time have you spent, to figure out that solution. Never I've heard of something like 'CTFontManagerRegisterGraphicsFont'. Guess, I will try this the next days. – LukeSideWalker Feb 08 '21 at 23:36
  • I happened to run into a scenario recently where my custom font wasn't getting loaded inside a Catalyst application, so I had a running head start having figured out how to deal with that situation. Then it was just a matter of applying it to a framework and making sure it worked there. – jnpdx Feb 08 '21 at 23:45
  • 2
    This code is outdated, look here https://stackoverflow.com/questions/30507905/xcode-using-custom-fonts-inside-dynamic-framework and search for another Register method ( `CTFontManagerRegisterFontsForURL` ). Found in the GraphicFont method documentation: "Fonts that are backed by files should be registered using CTFontManagerRegisterFontsForURL(_:_:_:)." – itMaxence Aug 02 '21 at 15:34
4

I had a similar issue sharing a font with a widget extension - the framework I was using was already built using code similar to the accepted answer (CTFontManagerRegisterGraphicsFont), and it worked just fine in apps themselves, but when I tried to use the framework and the fonts in my widget, it failed to render any of my view code.

What eventually solved it for me was the change suggested in the comment by @itMaxence and in this Apple thread - using CTFontManagerRegisterFontsForURL instead allowed it to work both in the app and in the widget extension.

Just wanted to highlight that comment in case anyone like me stumbles across this thread in the future.