我可以将自定义字体嵌入到捆绑包中并从ios框架访问它吗?
我正在创建一个ios框架及其捆绑包,用于打包资源(笔尖、图像、字体),我正在尝试在捆绑包中嵌入一个自定义字体,但我无法从框架中加载它,可能吗 1) 我可以使用以下命令本地化字体文件:我可以将自定义字体嵌入到捆绑包中并从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]; 我用“应用程序提供
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)
。最后,我还试图删除toCFRelease
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()
}
}
}