Can I embed a custom font in a bundle and access it from an ios framework?

后端 未结 7 1290
北荒
北荒 2020-12-13 02:35

I\'m creating an ios framework with its bundle for packaging ressources (nib, images, fonts) and I\'m trying to embed a custom font

相关标签:
7条回答
  • 2020-12-13 02:55

    Updated for Swift 4/5 and changed to throw errors instead of returning a Bool.

    enum FontLoadingError: Error {
        case fileNotFound
        case unreadableFontData
    }
    
    func loadCustomFont(name: String) throws {
        guard let fontURL = frameworkBundle.url(forResource: name, withExtension: "ttf") else {
            throw FontLoadingError.fileNotFound
        }
    
        guard
            let provider = CGDataProvider(url: fontURL as CFURL),
            let font = CGFont(provider)
        else {
            throw FontLoadingError.unreadableFontData
        }
    
        var cfError: Unmanaged<CFError>?
        CTFontManagerRegisterGraphicsFont(font, &cfError)
    
        if let error = cfError as? Error {
            throw error
        }
    }
    
    0 讨论(0)
  • 2020-12-13 02:59

    This is a new method that lets you load fonts dynamically without putting them in your Info.plist: http://www.marco.org/2012/12/21/ios-dynamic-font-loading

    0 讨论(0)
  • 2020-12-13 03:05

    In swift, I use the code below :

    public class func loadMyCustomFont(name:String) -> Bool{
      let fontPath = self.frameworkBundle().pathForResource(name, ofType: "ttf")!
      let inData = NSData(contentsOfFile:fontPath)
      var error: Unmanaged<CFError>?
      let provider = CGDataProviderCreateWithCFData(inData)
      if let font = CGFontCreateWithDataProvider(provider) {
         CTFontManagerRegisterGraphicsFont(font, &error)
         if error != nil {
           print(error) //Or logged it
           return false
         }
    
    
          }
           return true
       }
    

    The frameworkBundle method :

    class func frameworkBundle() -> NSBundle{
           var bundle = NSBundle()
           var predicate = dispatch_once_t()
           dispatch_once(&predicate) {
              let mainBundlePath = NSBundle.mainBundle().bundlePath
              let frameworkBundlePath = mainBundlePath.stringByAppendingString("/myFramework.framework/")
              bundle = NSBundle(path: frameworkBundlePath)!
           }
           return bundle
     }
    

    Exemple of call : (In my case, i added all fonts in the Fonts folder)

    YouClassName.loadMyCustomFont("Fonts/Roboto-Regular")
    

    Your corrections and remarks are welcome !

    0 讨论(0)
  • 2020-12-13 03:09

    You can use this extension if you have the font in a file/bundle.

    public extension UIFont {
    
        static func register(from url: URL) throws {
            if !FileManager.default.fileExists(atPath: url.path) {
                throw VError.incorrectFont
            }
    
            var error: Unmanaged<CFError>?
    
            guard CTFontManagerRegisterFontsForURL(url as CFURL, .process, &error) else {
                throw error!.takeUnretainedValue()
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 03:10

    Here is way I implemented it for my fmk based on the solution provided by "David M." This solution doesn't require to add the reference to the font in the plist.

    1) Class that load the font

    - (void) loadMyCustomFont{
        NSString *fontPath = [[NSBundle frameworkBundle] pathForResource:@"MyFontFileNameWithoutExtension" ofType:@"ttf"];
        NSData *inData = [NSData dataWithContentsOfFile:fontPath];
        CFErrorRef error;
        CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
        CGFontRef font = CGFontCreateWithDataProvider(provider);
        if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
            CFStringRef errorDescription = CFErrorCopyDescription(error);
            NSLog(@"Failed to load font: %@", errorDescription);
            CFRelease(errorDescription);
        }
        CFRelease(font);
        CFRelease(provider);
    }
    

    2) Category on NSBundle to get access to my bundle

    + (NSBundle *)frameworkBundle {
        static NSBundle* frameworkBundle = nil;
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
            NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath];
            NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:@"MyBundleName.bundle"];
            frameworkBundle = [NSBundle bundleWithPath:frameworkBundlePath];
        });
        return frameworkBundle;
    }
    

    Note: require to integrate CoreText in your project

    0 讨论(0)
  • 2020-12-13 03:11

    Swift 3 version of @Ali-ABBAS's answer, also updated to up-wrap options instead of force unwrapping.

    fileprivate func loadCustomFont(name:String) -> Bool{
    
        guard let fontPath = frameworkBundle.path(forResource: name, ofType: "ttf") else {
            return false
        }
    
        guard let inData = NSData(contentsOfFile:fontPath) else {
            return false
        }
    
    
        guard let provider = CGDataProvider(data: inData) else {
            return false
        }
    
        let font = CGFont(provider)
        var error: Unmanaged<CFError>?
        CTFontManagerRegisterGraphicsFont(font, &error)
        guard error == nil else {
            print(error) //Or logged it
            return false
        }
    
        return true
    }
    
    0 讨论(0)
提交回复
热议问题