iOS13新操做 安裝自定義字體

Install Fonts?

Created by shuimu 2020/05/25bash

安裝字體受權

What? Font Provider Apps

提交到應用商店的容許在操做系統中提供系統範圍內可用字體的應用程序。app

How? 資質

要建立一個字體提供app,須要知足兩個條件:async

  1. 應用必須包含 Fonts 相關的 entitlement
  2. 當應用被提交到商店時,須要同時提交應用中提供給系統的全部字體。
    • 字體必須是應用包的一部分,或者是按需加載的資源。
    • 支持的格式:ttf、otf、ttc(近代的,以及它的變體。不支持舊字體格式,如suitcase、postscript等)。
    • 系統不容許字體提供app任意安裝字體,字體需提交到應用商店,並通過一個相似 macOS 中的 Font Book 的簡單驗證流程。

Make it.

獲取字體能力

Capabilities中找到並添加 Fonts ide

Fonts entitlement

Fonts 包含兩個選項: post

Font Privileges

  • Install Fonts:安裝字體。字體

    使app可以在系統範圍內提供字體ui

  • Use Installed Fonts:使用已安裝的字體。url

    默認狀況下,應用程序沒法訪問用戶安裝的字體。應用程序須要選擇這個功能,才能看到這些字體。spa

瞭解相關APIs

CoreText/CTFontManager.h,引入了相關的APIs:操作系統

有三種註冊字體方法:
  • CTFontManagerRegisterFontURLs

    使用指向字體文件的FontURLs

  • CTFontManagerRegisterFontDescriptors

    經過使用字體描述符註冊字體

  • CTFontManagerRegisterFontsWithAssetNames

    註冊存在於應用程序中的字體資源

移除註冊字體
  • CTFontManagerUnregisterFontURLs
  • CTFontManagerUnegisterFontDescriptors
查看字體
  • CTFontManagerCopyRegisteredDescriptors

    字體提供app用於訪問已註冊的字體

  • CTFontManagerRequestFonts

字體應用或用戶的指望

  • 首先,應用程序應該提供一個有意義的UI,用戶能夠在其中瀏覽字體、安裝和刪除字體。

    這是必要的,由於在iOS中,咱們沒有一個應用程序能夠像在macOS中那樣在操做系統中安裝字體。

  • 此外,應用程序應該響應系統字體更改通知。

    緣由是:用戶可以在設置中刪除字體,且應用應該注意到這一點並及時更新它的UI。

  • 最後,若是你是一個字體提供程序,它計劃提供一組很大的字體給用戶,一個很大的字體庫。

    咱們強烈建議您使用按需資源並將字體打包到資產目錄中。

    這是一種更有效的交付用戶所需字體的方式,由於用戶將只下載他們實際將要使用的字體。而不是下載一個巨大的字體庫。

簡單示例

註冊字體系統通知

添加觀察者,以便響應系統字體變動通知。

e.g.

  • 當一個新字體被註冊到系統中的時候;
  • 當一個字體從系統中被移除的時候;
  • ...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fontsChangedNotification:) name:(__bridge NSString *)kCTFontManagerRegisteredFontsChangedNotification object:nil];
複製代碼
- (void)fontsChangedNotification:(id)noti {
    
    // 處理字體更新 ...
    [FontProvider updateRegisterdFonts];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        // 更新相關UI ...
    });
}

複製代碼

註冊字體

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;
    });
}
複製代碼

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;
    });
}
複製代碼

註冊方法中部分參數說明:

  • CTFontManagerScope scope, // 做用域,定義註冊的可用性和生存期。設置爲 kCTFontManagerScopePersistent 以便其餘app可使用該字體
  • bool enabled, // 布爾值,標示該字體是否可以經過 CTFontManagerRequestFonts 被發現。通常選擇true。

移除字體

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

複製代碼

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;
    });
}
複製代碼

查看已註冊字體

CTFontManagerCopyRegisteredFontDescriptors 僅可獲取字體提供應用本身註冊的字體

- (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];
    }
}
複製代碼

注意事項

  • 字體提供應用,僅可管理(移除)本身註冊的字體,沒法管理其餘字體提供應用所註冊的字體。
  • 字體沒法被重複註冊。
  • 當字體提供應用被卸載,其所註冊字體將一併被移除。
  • 字體使用者,實例化字體時,須要檢查所使用字體是否存在,由於它可能由於各類緣由而被改變。
  • 註冊字體在何處被管理:字體提供應用程序,或者【通用-設置-字體】。
相關文章
相關標籤/搜索