skip to Main Content

So I have xcframework which have fonts file (from react-native-vector-icons).

enter image description here

In test project (testApp), I am importing xcframework and I was expecting it to copy resources from my framework but unfortunately it doesn’t copy these fonts which are there inside the xcframework and I have to manually add it in Copy Bundle Resources.

For end user, I don’t want them to go inside framework and add manually.

In my framework, I have Cops Pods resources in Build Phase but haven’t done anything such which would tell the project consuming this framework to copy these fonts (or resources).

What do I need to do so that in project it copies fonts (or resources) by itself? instead of manually doing it?

2

Answers


  1. You need to register the fonts with the font manager. I did this extending UIFont

    extension UIFont {
        private class ModuleClass {}
        static func fontsURLs() -> [URL] {
            let bundle = Bundle(for: ModuleClass.self)
            let fileNames = ["Feather"]
    
            return fileNames.compactMap { fontName in
                bundle.url(forResource: fontName, withExtension: "ttf")
            }
        }
        
        /// Registers the specified graphics font with the font manager.
        /// - Parameter url: Bundle URL of the font to register
        /// - Throws: If font cannot be registered
        static func register(from url: URL) throws {
            guard let fontDataProvider = CGDataProvider(url: url as CFURL) else {
                throw FontError.dataProviderNotCreated(message: "Could not create font data provider for (url).")
            }
            
            guard let font = CGFont(fontDataProvider) else {
                throw FontError.fontNotCreated(message: "Could not create font data provider for (url).")
            }
            
            var error: Unmanaged<CFError>?
            guard CTFontManagerRegisterGraphicsFont(font, &error) else {
                throw error?.takeUnretainedValue() ?? FontError.fontNotRegistered
            }
        }
    }
    

    Then, you need use this.

    public extension UIFont {
    /// Registers the specified graphics font with the font manager.
        /// Registered fonts participate in font descriptor matching.
        static func registerFonts() {
            let urls = fontsURLs()
            for url in urls {
                do {
                    try register(from: url)
                } catch {
                    debugPrint(error)
                }
            }
        }
    }
    

    and in your main project (app) register the fonts

    // In AppDelegate.swift
    import YourModule
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        UIFont.registerFonts()
        return true
    }
    
    Login or Signup to reply.
  2. If you distribute your xcframework using Cocoapods then you can have any resource file automatically copied in the destination .app bundle by Cocoapods.

    In your podspec you define the resources you need to copy and the xcframework (and NO spec.sources):

    spec.resources = ['Fonts/EncodeSans-ExtraBold.ttf']
    spec.vendored_frameworks = 'Example.xcframework'
    

    Or from within the xcframework:

    spec.resources = ['Example.xcframework/<a path>/EncodeSans-ExtraBold.ttf']
    spec.vendored_frameworks = 'Example.xcframework'
    

    When you execute pod install Cocoapods will create a "[CP] Copy Pods Resources" phase that will copy in the destination app whatever you have defined in the resources:

    enter image description here

    To avoid collisions(the user or other pod might copy the same file), better use resource_bundles instead of resources.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search