我可以将自定义字体嵌入到捆绑包中并从ios框架访问它吗?

我可以将自定义字体嵌入到捆绑包中并从ios框架访问它吗?,ios,objective-c,frameworks,bundle,Ios,Objective C,Frameworks,Bundle,我正在创建一个ios框架及其捆绑包,用于打包资源(笔尖、图像、字体),我正在尝试在捆绑包中嵌入一个自定义字体,但我无法从框架中加载它,可能吗 1) 我可以使用以下命令本地化字体文件: objc NSString*fontPath=[[NSBundle frameworkBundle]pathForResource:@“MyCustomFont”类型:@“ttf”]; 2) 但我在字体列表中找不到: objc NSArray*数组=[UIFont familyNames]; 我用“应用程序提供

我正在创建一个ios框架及其捆绑包,用于打包资源(笔尖、图像、字体),我正在尝试在捆绑包中嵌入一个自定义字体,但我无法从框架中加载它,可能吗

1) 我可以使用以下命令本地化字体文件:
objc
NSString*fontPath=[[NSBundle frameworkBundle]pathForResource:@“MyCustomFont”类型:@“ttf”];
2) 但我在字体列表中找不到:
objc
NSArray*数组=[UIFont familyNames];
我用“应用程序提供的字体”将我的字体名称包含在捆绑包的plist中,但没有成功,我也在app info plist中尝试过,将其包含在框架ressource中,但没有成功

我可以从bundle加载nib和图像(通过使用bundle的名称作为前缀),但不能加载字体。有什么想法吗

编辑:我看到了以下帖子:,但问题只是“我可以在iPhone应用程序中嵌入自定义字体吗?”而不是“我可以在外部框架/捆绑包中嵌入自定义字体吗?”它还引用了动态加载,这很有趣,但它使用的是私有api,这对于框架来说是不可用的解决方案


感谢

这是一种新方法,允许您动态加载字体,而无需将字体放入信息中。plist:

以下是我基于“David M”提供的解决方案为fmk实现字体的方法 此解决方案不需要在plist中添加对字体的引用

1) 类来加载字体

- (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) NSBundle上的类别以访问我的捆绑包

+ (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;
}

注意:需要将CoreText集成到您的项目中,我使用以下代码:

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
   }
调用示例:(在我的例子中,我在字体文件夹中添加了所有字体)

欢迎您的更正和评论Swift 3:

首先,不要从带有附加路径组件的main访问框架包。。。从其标识符实例化它。您可以获得如下字体URL:

static func fontsURLs() -> [URL] {
    let bundle = Bundle(identifier: "com.company.project.framework")!
    let fileNames = ["Roboto-Bold", "Roboto-Italic", "Roboto-Regular"]
    return fileNames.map({ bundle.url(forResource: $0, withExtension: "ttf")! })
}
我觉得有
UIFont
扩展来注册字体很好:

public extension UIFont {
    public static func register(from url: URL) throws {
        guard let fontDataProvider = CGDataProvider(url: url as CFURL) else {
            throw SVError.internal("Could not create font data provider for \(url).")
        }
        let font = CGFont(fontDataProvider)
        var error: Unmanaged<CFError>?
        guard CTFontManagerRegisterGraphicsFont(font, &error) else {
            throw error!.takeUnretainedValue()
        }
    }
}

@Ali ABBAS答案的Swift 3版本,也更新为包裹选项,而不是强制展开

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
}
fileprivate func loadCustomFont(名称:String)->Bool{
guard let fontPath=frameworkBundle.path(forResource:name,of type:“ttf”)else{
返回错误
}
guard let inData=NSData(contentsOfFile:fontPath)else{
返回错误
}
guard let provider=CGDataProvider(数据:inData)else{
返回错误
}
let font=CGFont(提供程序)
var错误:非托管?
CTFontManagerRegisterGraphicsFont(字体和错误)
保护错误==nil else{
打印(错误)//或记录它
返回错误
}
返回真值
}

为Swift 4/5更新,并更改为抛出错误,而不是返回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
    }
}
enum FontLoadingError:错误{
案例文件未找到
案例无法访问的数据
}
func loadCustomFont(名称:String)抛出{
guard let fontURL=frameworkBundle.url(用于资源:名称,扩展名为:“ttf”)else{
抛出FontLoadingError.fileNotFound
}
警卫
let provider=CGDataProvider(url:fontURL作为CFURL),
let font=CGFont(提供程序)
否则{
抛出FontLoadingError.unreadableFontData
}
var cfError:非托管?
CTFontManagerRegisterGraphicsFont(字体和cfError)
如果let error=cfError as?错误{
抛出错误
}
}

如果文件/捆绑包中有字体,则可以使用此扩展名

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()
        }
    }
}
公共扩展UIFont{
静态func寄存器(来自url:url)抛出{
如果!FileManager.default.fileExists(atPath:url.path){
抛出错误字体
}
var错误:非托管?
guard CTFontManagerRegisterFontsForURL(url为CFURL、.process和error)else{
抛出错误!.takeUnrepainedValue()
}
}
}

我找到了一个解决办法(仍然希望找到更好的解决方案)。包含框架的用户必须在其
info.plist
中添加对捆绑包中字体的引用:
UIAppFonts key=item0 value=BUNDLENAME.bundle/font\u FILENAME.ttf
非常感谢!您的方法帮助我获得了框架包,如下所示:
NSBundle*bundle=[NSBundle bundleForClass:self.class]不为我工作):我得到
线程1:EXC\u BREAKPOlNT(code=EXC\u ARM\u BREAKPOINT.subcode=0xdefe)
。最后,我还试图删除to
CFRelease
s,但没有起到任何作用……对我有效,您是否查看了验证问题。它提供了一个指向我提出的解决方案的链接,可能还有更多信息?需要注意的是,资源名称字符串必须是字体文件的名称,而不一定是字体名称。对我来说,它是
NSBundle.mainBundle().privateFrameworkPath
,而不是
NSBundle.mainBundle().bundlePath
此外,您还应检查函数的返回值
CTFontManagerRegisterGraphicsFont
调用。不是
错误
参数您应该强制展开选项,它们是可选的,因为它们可以为零,如果为零,应用程序将崩溃。使用
guard
语句提前打开并退出,或者如果没有,则使用
throw
。这样做有效-只需确保字体作为资源加载到文件资源管理器中,而不是像我一开始使用的那样加载到
Assets.xcsets
文件夹中……回答得很好!这是一条路要走。工作时略有变化。谢谢
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
}
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
    }
}
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()
        }
    }
}