I want to use a custom font within a Cocoapod, but I can't find anything on using a custom font within a static library. As there is no info.plist file, there is no where to tell the app what font to use.
Any ideas?
Go to search in the start menu. Search for Fonts in settings. Click on the Fonts Folder to open the Font folder. Drag and Drop or Copy and Paste the unzipped fonts files into the Fonts folder to install.
There is a way of using a custom font without adding anything to the plist file.
NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSURL *fontURL = [bundle URLForResource:<#fontName#> withExtension:@"otf"/*or TTF*/]; NSData *inData = [NSData dataWithContentsOfURL:fontURL]; CFErrorRef error; CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData); CGFontRef font = CGFontCreateWithDataProvider(provider); if (!CTFontManagerRegisterGraphicsFont(font, &error)) { CFStringRef errorDescription = CFErrorCopyDescription(error); NSLog(@"Failed to load font: %@", errorDescription); CFRelease(errorDescription); } CFSafeRelease(font); CFSafeRelease(provider);
You also need the CFSafeRelease
function for this to work.
void CFSafeRelease(CFTypeRef cf) { if (cf != NULL) { CFRelease(cf); } }
Source: Loading iOS fonts dynamically.
Swift equivalent:
extension UIFont { static func registerFont(bundle: Bundle, fontName: String, fontExtension: String) -> Bool { guard let fontURL = bundle.url(forResource: fontName, withExtension: fontExtension) else { fatalError("Couldn't find font \(fontName)") } guard let fontDataProvider = CGDataProvider(url: fontURL as CFURL) else { fatalError("Couldn't load data from the font \(fontName)") } guard let font = CGFont(fontDataProvider) else { fatalError("Couldn't create font from data") } var error: Unmanaged<CFError>? let success = CTFontManagerRegisterGraphicsFont(font, &error) guard success else { print("Error registering font: maybe it was already registered.") return false } return true } }
If I understand correctly, you are trying to provide a font with your Cocoapod, and you intent the iOS apps which include the pod to be able to use your custom font.
This post_install
hook seems to work:
Pod::Spec.new do |s| # ... s.resources = "Resources/*.otf" # ... s.post_install do |library_representation| require 'rexml/document' library = library_representation.library proj_path = library.user_project_path proj = Xcodeproj::Project.new(proj_path) target = proj.targets.first # good guess for simple projects info_plists = target.build_configurations.inject([]) do |memo, item| memo << item.build_settings['INFOPLIST_FILE'] end.uniq info_plists = info_plists.map { |plist| File.join(File.dirname(proj_path), plist) } resources = library.file_accessors.collect(&:resources).flatten fonts = resources.find_all { |file| File.extname(file) == '.otf' || File.extname(file) == '.ttf' } fonts = fonts.map { |f| File.basename(f) } info_plists.each do |plist| doc = REXML::Document.new(File.open(plist)) main_dict = doc.elements["plist"].elements["dict"] app_fonts = main_dict.get_elements("key[text()='UIAppFonts']").first if app_fonts.nil? elem = REXML::Element.new 'key' elem.text = 'UIAppFonts' main_dict.add_element(elem) font_array = REXML::Element.new 'array' main_dict.add_element(font_array) else font_array = app_fonts.next_element end fonts.each do |font| if font_array.get_elements("string[text()='#{font}']").empty? font_elem = REXML::Element.new 'string' font_elem.text = font font_array.add_element(font_elem) end end doc.write(File.open(plist, 'wb')) end end
The hook finds the user project, and in the first target (you probably can complete this solution by asking CocoaPods to give you the real target) it looks for its Info.plist
file(s) (normally there is only one). Finally it looks for the UIAppFonts
key of the file, creates it if not found, and fill the array with the font names if they are not already there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With