Xcode: Using custom fonts inside Dynamic framework
Swift 4:
This is maybe an old thread but has updated @xaphod for swift 4 as all static and global variables are lazily initialised using dispatch_once.
extension UIFont {
// load framework font in application
public static let loadAllFonts: () = {
registerFontWith(filenameString: "SanFranciscoText-Regular.otf", bundleIdentifierString: "Fonts")
registerFontWith(filenameString: "SanFranciscoText-Medium.otf", bundleIdentifierString: "Fonts")
registerFontWith(filenameString: "SanFranciscoText-Semibold.otf", bundleIdentifierString: "Fonts")
registerFontWith(filenameString: "SanFranciscoText-Bold.otf", bundleIdentifierString: "Fonts")
registerFontWith(filenameString: "SanFranciscoText-LightItalic.otf", bundleIdentifierString: "Fonts")
}()
//MARK: - Make custom font bundle register to framework
static func registerFontWith(filenameString: String, bundleIdentifierString: String) {
let frameworkBundle = Bundle(for: MSAlertController.self)
let resourceBundleURL = frameworkBundle.url(forResource: bundleIdentifierString, withExtension: "bundle")
if let url = resourceBundleURL, let bundle = Bundle(url: url) {
let pathForResourceString = bundle.path(forResource: filenameString, ofType: nil)
if let fontData = NSData(contentsOfFile: pathForResourceString!), let dataProvider = CGDataProvider.init(data: fontData) {
let fontRef = CGFont.init(dataProvider)
var errorRef: Unmanaged<CFError>? = nil
if (CTFontManagerRegisterGraphicsFont(fontRef!, &errorRef) == false) {
print("Failed to register font - register graphics font failed - this font may have already been registered in the main bundle.")
}
}
}
else {
print("Failed to register font - bundle identifier invalid.")
}
}
}
Then you can call UIFont.loadAllfont
inside the appDelegate
Here's my version of John's answer, showing how to call the function if you have lots of fonts
import Foundation
extension UIFont {
@nonobjc static var loadAllFontsDO: dispatch_once_t = 0
class func initialsAvatarFont() -> UIFont {
loadAllFonts()
if let retval = UIFont(name: "MyFontName", size: kInitialsAvatarFontSize) {
return retval;
} else {
return UIFont.systemFontOfSize(kInitialsAvatarFontSize)
}
}
class func loadAllFonts() {
dispatch_once(&loadAllFontsDO) { () -> Void in
registerFontWithFilenameString("thefontfilename.ttf", bundleIdentifierString: "nameOfResourceBundleAlongsideTheFrameworkBundle")
// Add more font files here as required
}
}
static func registerFontWithFilenameString(filenameString: String, bundleIdentifierString: String) {
let frameworkBundle = NSBundle(forClass: AnyClassInYourFramework.self)
let resourceBundleURL = frameworkBundle.URLForResource(bundleIdentifierString, withExtension: "bundle")
if let bundle = NSBundle(URL: resourceBundleURL!) {
let pathForResourceString = bundle.pathForResource(filenameString, ofType: nil)
let fontData = NSData(contentsOfFile: pathForResourceString!)
let dataProvider = CGDataProviderCreateWithCFData(fontData)
let fontRef = CGFontCreateWithDataProvider(dataProvider)
var errorRef: Unmanaged<CFError>? = nil
if (CTFontManagerRegisterGraphicsFont(fontRef!, &errorRef) == false) {
NSLog("Failed to register font - register graphics font failed - this font may have already been registered in the main bundle.")
}
}
else {
NSLog("Failed to register font - bundle identifier invalid.")
}
}
}
I'm here a bit late, but I took PetahChristian's solution and created a Swift version in the form of an extension. This is working for me. I've found that when you try to get a font using a font name and a size using the regular way that it always looks in the main bundle for the font file, and there's no method that takes a bundle identifier as a parameter. It would be nice if Apple would make one.
Swift:
public extension UIFont {
public static func jbs_registerFont(withFilenameString filenameString: String, bundle: Bundle) {
guard let pathForResourceString = bundle.path(forResource: filenameString, ofType: nil) else {
print("UIFont+: Failed to register font - path for resource not found.")
return
}
guard let fontData = NSData(contentsOfFile: pathForResourceString) else {
print("UIFont+: Failed to register font - font data could not be loaded.")
return
}
guard let dataProvider = CGDataProvider(data: fontData) else {
print("UIFont+: Failed to register font - data provider could not be loaded.")
return
}
guard let font = CGFont(dataProvider) else {
print("UIFont+: Failed to register font - font could not be loaded.")
return
}
var errorRef: Unmanaged<CFError>? = nil
if (CTFontManagerRegisterGraphicsFont(font, &errorRef) == false) {
print("UIFont+: Failed to register font - register graphics font failed - this font may have already been registered in the main bundle.")
}
}
}
Usage Example:
UIFont.jbs_registerFont(
withFilenameString: "Boogaloo-Regular.ttf",
bundle: Bundle(identifier: "com.JBS.JBSFramework")!
)