Registering custom fonts from a framework in a widget extension

I want a widget to use the same custom fonts that the containing app uses. I do not want multiple copies of the font files in the app bundle. I put the font files into a framework shared by the app and the widget extension. I have code to register the fonts from the framework bundle using CTFontManagerRegisterGraphicsFont. That works from the app, but it does not work from the widget extension because it requires UIKit. (At least I think that's why it doesn't seem to work from my widget extension.)

Widgets cannot run UIKit code. Is there a way to programmatically register the fonts in a widget? If not is there a way I can make a UIAppFonts Info.plist entry point to a framework?

Post not yet marked as solved Up vote post of johnbrayton Down vote post of johnbrayton
4.5k views

Replies

CTFontManagerRegisterGraphicsFont or CTFontManagerRegisterFontsForURL does not require UIKit, it only requires CoreText framework. You should be able to use that in your widget code.
Thank you. I wonder if you can help me understand what I am doing wrong. I created a small sample project with this code shared between the app and the extension:

Code Block
class SharedFont {
    static let fontName = "Miso-Bold"
    static func registerFont() {
        guard let url = Bundle.main.url(forResource: "miso-bold", withExtension: "otf") else {
            print("could not find font file")
            return
        }
        print("registering font at \(url.absoluteString)")
        guard let fontDataProvider = CGDataProvider(url: url as CFURL) else {
            print("Could not create font data provider for \(url).")
            return
        }
        guard let font = CGFont(fontDataProvider) else {
            print("could not create font")
            return
        }
        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(font, &error) {
            print(error!.takeUnretainedValue())
        }
    }
}




If I call SharedFont.registerFont() in my AppDelegate didFinishLaunchingWithOptions method, the font is available to the app.

The font is in both the app target and in the widget target.

Either that same method does not work in a Widget extension, or perhaps I am putting it in the wrong place. I tried calling this in my TimelineProvider’s snapshot(…) function and in its timeline(…) function. The font does work in the extension or in the SwiftUI previews of the view in the extension. Is there a better place in a Widget extension to put this type of one-time initialization code that might let it work?
I have the same problem, were you able to solve it?
Were you able to get this to work? I got it to work in simulator, but not on an actual device..

To answer you question, I'm calling it in getTimeLine and getSnapShot. Also I'm using a static variable to flag 'already loaded' so it's not done more than once

I had this same issue - I was using essentially the exact same code, registering the font with CTFontManagerRegisterGraphicsFont, which worked just fine in my app, but when I tried to use the font in my widget view, it caused the entire view to not render.

Eventually I stumbled across this thread - as suggested there, I switched to using CTFontManagerRegisterFontsForURL and it worked - it rendered properly in both the app and the widget extension.

While I don't have context on exactly the difference between the two methods, Apple documentation does note that Fonts that are backed by files should be registered using CTFontManagerRegisterFontsForURL(_:_:_:), which seems to suggest CTFontManagerRegisterFontsForURL is the appropriate method to use here in any case.

When I using CTFontManagerRegisterFontsForURL(::_:) registered in widget, Custom fonts can be displayed in the simulator, but not in the test iphone.

What causes this? How to solve it?

  • Have the same problem. I use CTFontManagerRegisterFontsForURL to register font, simulator works, but not work on my phone.

Add a Comment