Xcode: Using custom fonts inside Dynamic framework

前端 未结 9 1547
再見小時候
再見小時候 2020-12-04 17:52

I added custom font to a framework. I followed all the steps, but it doesn\'t work.

I am able to set the font in Interface Builder, but when I build the project it d

相关标签:
9条回答
  • 2020-12-04 18:21

    I made a mix of different answers in Swift 4.2 so props to the guys who came up with it!

    import UIKit
    import Foundation
    
    extension UIFont {
    
        private class MyDummyClass {}
    
        static func loadFontWith(name: String) {
            let frameworkBundle = Bundle(for: MyDummyClass.self)
            let pathForResourceString = frameworkBundle.path(forResource: name, ofType: "ttf")
            let fontData = NSData(contentsOfFile: pathForResourceString!)
            let dataProvider = CGDataProvider(data: fontData!)
            let fontRef = CGFont(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.")
            }
        }
    
        public static let loadMyFonts: () = {
            loadFontWith(name: "Exo-Black")
            loadFontWith(name: "Exo-Bold")
            loadFontWith(name: "Exo-Regular")    
        }()
    }
    

    And then call in Appdelegate

    UIFont.loadMyFonts
    
    0 讨论(0)
  • 2020-12-04 18:26

    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.")
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-04 18:26

    The following solution allows you to load all fonts with a certain extension automatically:

    static func registerFonts() {
        let fonts = Bundle(for: 
    OrientationMonitor.self).urls(forResourcesWithExtension: "ttf", subdirectory: nil)
        fonts?.forEach({ url in
            CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
        })
    }
    

    Make sure to replace OrientationMonitor with a class existing in your framework.

    0 讨论(0)
  • 2020-12-04 18:28

    Was able to do this with Swift 4, given that you can include resources directly in a framework bundle now:

    Typography.swift (in my framework)

    import Foundation
    
    private class MyDummyClass {}
    
    func loadFontWith(name: String) {
      let frameworkBundle = Bundle(for: MyDummyClass.self)
      let pathForResourceString = frameworkBundle.path(forResource: name, ofType: "otf")
      let fontData = NSData(contentsOfFile: pathForResourceString!)
      let dataProvider = CGDataProvider(data: fontData!)
      let fontRef = CGFont(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.")
      }
    }
    
    public func loadMyFonts() {
      loadFontWith(name: "ComicSansPro-Regular")
      loadFontWith(name: "ComicSansPro-Medium")
      loadFontWith(name: "ComicSansPro-Bold")
      loadFontWith(name: "ComicSansPro-ExtraBold")
    }
    

    I ended up requiring the loadMyFonts method to be called in the application's that use this framework's didFinishLaunchingWithOptions method in AppDelegate.swift.

    0 讨论(0)
  • 2020-12-04 18:31

    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

    0 讨论(0)
  • 2020-12-04 18:34

    You can load and use bundled custom fonts from your dynamic framework by implementing the +load method in your framework.

    In the load method, you locate the fonts in the bundle, then register them. This makes them available to the app, without having to specify them in the main project.

    + (void)load
    {
        static dispatch_once_t onceToken;
         dispatch_once(&onceToken, ^{
            // Dynamically load bundled custom fonts
    
            [self bible_loadFontWithName:kBIBLECustomFontBoldName];
            [self bible_loadFontWithName:kBIBLECustomFontBoldItalicName];
            [self bible_loadFontWithName:kBIBLECustomFontItalicName];
            [self bible_loadFontWithName:kBIBLECustomFontRegularName];
        });
    }
    
    + (void)bible_loadFontWithName:(NSString *)fontName
    {
         NSString *fontPath = [[NSBundle bundleForClass:[BIBLE class]] pathForResource:fontName ofType:@"otf"];
         NSData *fontData = [NSData dataWithContentsOfFile:fontPath];
    
         CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)fontData);
    
         if (provider)
         {
            CGFontRef font = CGFontCreateWithDataProvider(provider);
    
             if (font)
             {
                 CFErrorRef error = NULL;
                 if (CTFontManagerRegisterGraphicsFont(font, &error) == NO)
                 {
                     CFStringRef errorDescription = CFErrorCopyDescription(error);
                     NSLog(@"Failed to load font: %@", errorDescription);
                     CFRelease(errorDescription);
                 }
    
                 CFRelease(font);
            }
    
            CFRelease(provider);
        }
    }
    
    0 讨论(0)
提交回复
热议问题