Подтвердить что ты не робот

Как добавить пользовательский шрифт в Cocoapod?

Я хочу использовать пользовательский шрифт внутри Cocoapod, но я не могу ничего найти при использовании пользовательского шрифта в статической библиотеке. Поскольку нет файла info.plist, нет места, где можно сообщить приложению, какой шрифт использовать.

Любые идеи?

4b9b3361

Ответ 1

Если я правильно понимаю, вы пытаетесь предоставить шрифт своим Cocoapod, и вы намерены использовать приложения iOS, которые включают в себя модуль, чтобы использовать свой собственный шрифт.

Этот трюк post_install, похоже, работает:

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

Крюк находит пользовательский проект и в первой цели (вы, вероятно, можете завершить это решение, попросив CocoaPods дать вам реальную цель), он ищет файлы Info.plist (обычно есть только один), Наконец, он ищет ключ UIAppFonts файла, создает его, если не найден, и заполняет массив именами шрифтов, если они еще не существуют.

Ответ 2

Существует способ использовать пользовательский шрифт, не добавляя ничего в файл plist.

    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);

Вам также нужна функция CFSafeRelease, чтобы это работало.

void CFSafeRelease(CFTypeRef cf) {
    if (cf != NULL) {
        CFRelease(cf);
    }
}

Источник: Динамическая загрузка шрифтов iOS.

Свифт эквивалент:

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
    }
}

Ответ 3

Для тех из вас, кто нашел это в 2018+, я получил пользовательские шрифты для работы с поддержкой конструктора интерфейсов (XCode 9) с этими двумя шагами:

  1. Добавьте свои шрифты в пакет ресурсов

    s.resource_bundles = {
      'PodName' => ['PodName/**/*.{ttf}']
    }
    
  2. Загружайте шрифты во время выполнения, используя ответ адама выше

    #import <CoreText/CoreText.h>
    
    void CFSafeRelease(CFTypeRef cf) { // redefine this
      if (cf != NULL) {
        CFRelease(cf);
      }
    }
    
    
    + (void) loadFonts {
      NSBundle *frameworkBundle = [NSBundle bundleForClass:self.classForCoder];
      NSURL *bundleURL = [[frameworkBundle resourceURL] URLByAppendingPathComponent:@"PodName.bundle"];
      NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];
    
      NSURL *fontURL = [bundle URLForResource:@"HindMadurai-SemiBold" withExtension:@"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);
    }
    

Ответ 4

Ну, ИДК, если это может быть ответом, но вы также можете посмотрите на cocoapod, которому нужен шрифт, вот так: https://github.com/parakeety/GoogleFontsiOS

Библиотека содержит много шрифтов, мне нужен был Chivo, поэтому я добавил модуль 'GoogleFontsiOS/Chivo' и использовал его вместо написания кода загрузки шрифтов самостоятельно.

Ответ 5

Реализация Swift 5

Я смог решить эту проблему, создав следующий класс в моем Cocoapod, затем просто вызвав CustomFonts.loadAll() из моего основного приложения AppDelegate.swift. После этого я могу просто использовать такой шрифт в своем приложении:

let myFont = CustomFonts.Style.regular.font

Обратите внимание, что перечисление Style необязательно, это просто удобный способ разделения проблем. Вы также можете просто позвонить:

let myFont = UIFont(name: "SourceSansPro-SemiBold", size: 14)

import CoreText

public class CustomFonts: NSObject {

  public enum Style: CaseIterable {
    case mono
    case regular
    case semibold
    public var value: String {
      switch self {
      case .mono: return "SourceCodePro-Medium"
      case .regular: return "SourceSansPro-Regular"
      case .semibold: return "SourceSansPro-SemiBold"
      }
    }
    public var font: UIFont {
      return UIFont(name: self.value, size: 14) ?? UIFont.init()
    }
  }

  // Lazy var instead of method so it only ever called once per app session.
  public static var loadFonts: () -> Void = {
    let fontNames = Style.allCases.map { $0.value }
    for fontName in fontNames {
      loadFont(withName: fontName)
    }
    return {}
  }()

  private static func loadFont(withName fontName: String) {
    guard
      let bundleURL = Bundle(for: self).url(forResource: "[CococpodName]", withExtension: "bundle"),
      let bundle = Bundle(url: bundleURL),
      let fontURL = bundle.url(forResource: fontName, withExtension: "ttf"),
      let fontData = try? Data(contentsOf: fontURL) as CFData,
      let provider = CGDataProvider(data: fontData),
      let font = CGFont(provider) else {
        return
    }
    CTFontManagerRegisterGraphicsFont(font, nil)
  }

}