Install Fonts?

Created by shuimu 2020/05/25

Install font authorization

What? Font Provider Apps

Applications submitted to the App Store that allow system-wide fonts to be available in the operating system.

How? qualification

To create a font to provide an app, two conditions need to be met:

  1. The application must containFontsThe relevantentitlement.
  2. When your app is submitted to the store, you need to submit all the fonts that your app provides to the system.
    • Fonts must be part of an application package or an on-demand resource.
    • Supported formats: TTF, OTF, TTC (recent, and its variants). Old font formats, such as Suitcase, Postscript, etc.) are not supported.
    • Fonts are not allowed to be installed in any Font provider app. Fonts must be submitted to the App Store and undergo a simple verification process similar to Font Book in macOS.

Make it.

Get font ability

Find and add Fonts in Capabilities

Fonts entitlement

Fonts contain two options:

Font Privileges

  • Install Fonts: Install Fonts.

    Enable the APP to provide fonts system-wide

  • Use Installed Fonts: Use Installed Fonts.

    By default, the application does not have access to user-installed fonts. The application needs to select this feature to see these fonts.

Learn about APIs

CoreText/ ctfontManager.h, which introduces related APIs:

There are three ways to register fonts:
  • CTFontManagerRegisterFontURLs

    Use FontURLs that point to font files

  • CTFontManagerRegisterFontDescriptors

    Register fonts by using font descriptors

  • CTFontManagerRegisterFontsWithAssetNames

    Register font resources that exist in your application

Remove registered fonts
  • CTFontManagerUnregisterFontURLs
  • CTFontManagerUnegisterFontDescriptors
Look at the font
  • CTFontManagerCopyRegisteredDescriptors

    Fonts provide app for accessing registered fonts

  • CTFontManagerRequestFonts

Font application or user expectations

  • First, the application should provide a meaningful UI in which the user can browse, install, and delete fonts.

    This is necessary because in iOS, we don’t have an application that can install fonts in the operating system like we do in macOS.

  • In addition, the application should respond to system font change notifications.

    The reason: users can remove fonts from their Settings, and the app should be aware of this and update its UI.

  • Finally, if you are a font provider, it plans to provide users with a set of very large fonts, a very large font library.

    We strongly recommend that you use on-demand resources and package fonts into an asset catalog.

    This is a more efficient way to deliver fonts that users need, because users will only download the fonts they will actually use. Instead of downloading a huge font library.

A simple example

Register font system notifications

Add an observer to respond to system font change notifications.

e.g.

  • When a new font is registered in the system;
  • When a font is removed from the system;
  • .
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fontsChangedNotification:) name:(__bridge NSString *)kCTFontManagerRegisteredFontsChangedNotification object:nil];
Copy the code
- (void) fontsChangedNotification: (id) noti {/ / processing font updates... [FontProvider updateRegisterdFonts]; Dispatch_async (dispatch_get_main_queue(), ^{// Update related UI... }); }Copy the code

Register font

Register from fontURLs.

- (void)registerFontWithFontURL:(NSURL *)fontURL {
    NSURL *urls[] = {fontURL};
    CFArrayRef fontURLs = CFArrayCreate(kCFAllocatorDefault, (void *)urls, (CFIndex)1, NULL);
    
    CTFontManagerRegisterFontURLs(fontURLs, kCTFontManagerScopePersistent, true, ^bool(CFArrayRef  _Nonnull errors, bool done) {
        if (CFArrayGetCount(errors) > 0) {
            // regist failed
            CFErrorRef cfError = (CFErrorRef)CFArrayGetValueAtIndex(errors, 0);
            NSError *error = (__bridge_transfer NSError *)cfError;
            NSLog(@"Regist Font Failed: %@", [error localizedDescription]);
            return false;
        }
        return true;
    });
}
Copy the code

Register from an asset catalog.

- (void)registerFontWithFontAssetName:(NSString *)fontAssetName {
    NSString *values[] = {fontAssetName};
    CFArrayRef arrRef = CFArrayCreate(kCFAllocatorDefault, (void *)values, (CFIndex)1, NULL);
    
    CTFontManagerRegisterFontsWithAssetNames(arrRef, nil, kCTFontManagerScopePersistent, true, ^bool(CFArrayRef  _Nonnull errors, bool done) {
        if (CFArrayGetCount(errors) > 0) {
            // regist failed
            CFErrorRef cfError = (CFErrorRef)CFArrayGetValueAtIndex(errors, 0);
            NSError *error = (__bridge_transfer NSError *)cfError;
            NSLog(@"Regist Font Failed: %@", [error localizedDescription]);
            return false;
        }
        return true;
    });
}
Copy the code

Some parameters in the registration method are described as follows:

  • CTFontManagerScope scope, // Scope, defines the availability and lifetime of a registration. Set tokCTFontManagerScopePersistentSo that other apps can use the font
  • Bool enabled, // A Boolean value indicating whether the font can passCTFontManagerRequestFontsHas been found. Generally true is selected.

Remove the font

Unregister by FontURLs.

- (void)unregisterFontWithFontURL:(NSURL *)fontURL {
    NSURL *urls[] = {fontURL};
    CFArrayRef fontURLs = CFArrayCreate(kCFAllocatorDefault, (void *)urls, (CFIndex)1, NULL);
    
    CTFontManagerUnregisterFontURLs(fontURLs, kCTFontManagerScopePersistent, ^bool(CFArrayRef  _Nonnull errors, bool done) {
        if (CFArrayGetCount(errors) > 0) {
            // regist failed
            CFErrorRef cfError = (CFErrorRef)CFArrayGetValueAtIndex(errors, 0);
            NSError *error = (__bridge_transfer NSError *)cfError;
            NSLog(@"Regist Font Failed: %@", [error localizedDescription]);
            return false;
        }
        return true;
    });
}

Copy the code

Unregister by Font Descriptor.

- (void)unregisterFontWithFontDescriptor:(UIFontDescriptor *)fontDescriptor {
 
    CTFontDescriptorRef fontDescriptors[] = {(__bridge CTFontDescriptorRef)fontDescriptor};
    CTFontManagerUnregisterFontDescriptors(CFArrayCreate(kCFAllocatorDefault, (void *)fontDescriptors, (CFIndex)1, NULL), kCTFontManagerScopePersistent, ^bool(CFArrayRef  _Nonnull errors, bool done) {
        if (CFArrayGetCount(errors) > 0) {
            // regist failed
            CFErrorRef cfError = (CFErrorRef)CFArrayGetValueAtIndex(errors, 0);
            NSError *error = (__bridge_transfer NSError *)cfError;
            NSLog(@"Unregist Font Failed: %@", [error localizedDescription]);
            return false;
        }
        return true;
    });
}
Copy the code

View registered fonts

CTFontManagerCopyRegisteredFontDescriptors only provide application to register font available fonts

- (void)getRegisteredFonts {

    [FontProvider.registeredFonts removeAllObjects];
    
    CFArrayRef registerdDescriptors = CTFontManagerCopyRegisteredFontDescriptors(kCTFontManagerScopePersistent, true);
    for(CFIndex i = 0; i < CFArrayGetCount(registerdDescriptors); i ++) { CTFontDescriptorRef fontDescriptorRef = CFArrayGetValueAtIndex(registerdDescriptors, i); UIFontDescriptor *fontDescriptor = (__bridge_transfer UIFontDescriptor *)fontDescriptorRef; // save registered fonts ... [FontProvider.registeredFonts addObject:fontDescriptor]; }}Copy the code

Matters needing attention

  • Font provider applications can only manage (remove) their own registered fonts, can not manage other font provider applications registered fonts.
  • Font could not be registered twice.
  • When the font provider application is uninstalled, all registered fonts are removed.
  • Font users, when instantiating a font, need to check whether the font being used exists because it can change for various reasons.
  • Where registered fonts are managed: Font provider application, or Generic – Settings – Fonts.