16

I would like to allow my application users to use their own fonts in the app, by copying them inside the Documents directory (through iTunes). However, I can't find a way to use custom fonts in this way, since the right way to do it depends on using the UIAppFonts key in the app's Info.plist.

Is there any way to override this during runtime?

Thanks.

Vicarius
  • 304
  • 3
  • 7

4 Answers4

19

I know this is an old question, but I was trying to do the same today and found a way using CoreText and CGFont.

First be sure you add the CoreText framework and

#import <CoreText/CoreText.h>

Then this should do it (in this example I am using a font I previously downloaded and saved to a fonts directory inside the Documents directory):

NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentsDirectory = [paths objectAtIndex:0];
    NSString * fontPath = [documentsDirectory stringByAppendingPathComponent:@"Fonts/Chalkduster.ttf"];
    NSURL * url = [NSURL fileURLWithPath:fontPath];
    CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)url);
    CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
    NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
    CGDataProviderRelease(fontDataProvider);
    CFErrorRef error;
    CTFontManagerRegisterGraphicsFont(newFont, &error);
    CGFontRelease(newFont);

    UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

Hope it helps anyone stumbling across this question!

Pablo
  • 613
  • 5
  • 12
  • Hello I have one Question .. Actually At Run Time I am taking font from web service and than can i install it and use it and how ? – Hardik Vyas Mar 21 '16 at 07:02
  • You can save it to your app's Documents directory and then load it using the code above. – Pablo Mar 21 '16 at 22:16
  • CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider); application hangs on this line for forever. – dev gr Jan 04 '17 at 11:29
6

Try this one

#import "MBProgressHUD.h"
#import <CoreText/CoreText.h>


- (void)viewDidLoad
{
    NSURL *fileNameURL=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/"];
    NSMutableURLRequest *filenameReq=[[NSMutableURLRequest alloc] initWithURL:fileNameURL];
    NSData *responseData=[NSURLConnection sendSynchronousRequest:filenameReq returningResponse:nil error:nil];

    NSDictionary* json = [NSJSONSerialization
                          JSONObjectWithData:responseData
                          options:kNilOptions
                          error:nil];


    NSString *fontFileName=[[[json valueForKey:@"filename"] componentsSeparatedByString:@"."] objectAtIndex:0];

    NSLog(@"file name is %@",fontFileName);

    NSURL *url=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/blob?download"];

    NSMutableURLRequest *request=[[NSMutableURLRequest alloc] initWithURL:url];

    __block NSError *error;
    __block NSURLResponse *response;

    MBProgressHUD *hud=[MBProgressHUD showHUDAddedTo:self.view animated:YES];
    hud.labelText=@"Changing Font..";

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

        NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
        NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideAllHUDsForView:self.view animated:YES];

            NSFileManager *fm=[NSFileManager defaultManager];

            if (![fm fileExistsAtPath:filePath]) {
                [urlData writeToFile:filePath atomically:YES];
            }

            NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
            NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

            NSURL * fonturl = [NSURL fileURLWithPath:filePath];
            CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fonturl);

            CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
            NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
            CGDataProviderRelease(fontDataProvider);
            CFErrorRef fonterror;
            CTFontManagerRegisterGraphicsFont(newFont, &fonterror);

            CGFontRelease(newFont);

            UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

            [txt_UserName setFont:finalFont];
        });
    });

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

Sample Code Here

It will look like

enter image description here

Prince Kumar Sharma
  • 12,591
  • 4
  • 59
  • 90
1

There is a class created by the guys at Zynga which makes it possible to load any custom fonts: FontLabel.

You have to call [FontManager loadFont:] in your application startup (for example in your app delegate) for each font that you want to use in your app.

Therefore is non-trivial to iterate in the Documents folder looking for .ttf files (the library works only with ttf font).

A little notice: this class use a subclass of UILabel.

Luca Bernardi
  • 4,191
  • 2
  • 31
  • 39
1
extension UIFont {

    func registerNewFontFromAppBundle(withSize: CGFloat) {
        guard let filePath = Bundle.main.url(forResource: "Art Brewery", withExtension: "ttf") else { return }
        guard let dataProvider = CGDataProvider(url: filePath as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
        }
    }

    func registerNewFontFromDownloadedFiles(withSize: CGFloat) {
         guard let filePath = FileUtils().getFilePathAtDocumentFolder(fileName: "Art Brewery.ttf") else { return }

        if FileUtils.fileExists(atPath: filePath) {
          let url = URL(fileURLWithPath: filePath)
        guard let dataProvider = CGDataProvider(url: url as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
            CurrentTheme.shared.currentFontName = cgFont.postScriptName! as String
        }
    }

    }
}

Usage :

UIFont.registerNewFontFromAppBundle(withSize: 30)
UIFont.registerNewFontFromDownloadedFiles(withSize: 30)
mylabel.font =  CurrentTheme.shared.currentFont // saved the font in a Singleton
or 
mylabel.font = UIFont(name: CurrentTheme.shared.currentFontName, size: 30) // Saved the Font name to reuse
K Ravi Kumar
  • 71
  • 1
  • 2