Asset Catalog中的Font Asset是怎么定义的?

What's the definition of Font Asset in the Asset Catalog?

从iOS13开始,CTFontManager具有以下功能:

@discussion Font assets are extracted from the asset catalog and registered. This call must be made after the completion handler of either NSBundleResourceRequest beginAccessingResourcesWithCompletionHandler: or conditionallyBeginAccessingResourcesWithCompletionHandler: is called successfully.
Name the assets using Postscript names for individual faces, or family names for variable/collection fonts. The same names can be used to unregister the fonts with CTFontManagerUnregisterFontDescriptors. In iOS, fonts registered with the persistent scope are not automatically available to other processes. Other process may call CTFontManagerRequestFonts to get access to these fonts.

@param      fontAssetNames
            Array of font name assets in asset catalog.

...

CTFontManagerRegisterFontsWithAssetNames(_ fontAssetNames: CFArray, _ bundle: CFBundle?, _ scope: CTFontManagerScope, _ enabled: Bool, _ registrationHandler: ((CFArray, Bool) -> Bool)?)

但是,Asset Catalog 没有办法添加“字体资源”。

我尝试过的:

Data Asset 的 Contents.json 现在看起来像这样:

{
   "data" : [
    {
      "filename" : "Kanit-Regular.ttf",
      "idiom": "universal",
      "universal-type-identifier" : "public.truetype-ttf-font"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

像这样:

func registerFont() {
    var cfBundle: CFBundle?
    if let bundle = Bundle(for: type(of: self)) {
        cfBundle = CFBundleCreate(kCFAllocatorDefault, bundle.bundleURL as CFURL)
    }
    CTFontManagerRegisterFontsWithAssetNames(["Kanit-Regular"] as CFArray, cfBundle, .persistent, true) { (errors, done) -> Bool in
        print(errors)
        return done
    }
}

在此之后,打印 errors

▿ 1 element
  - 0 : Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument" UserInfo={CTFontManagerErrorFontAssetNameKey=(
    "Kanit-Regular"
)}

有什么办法让它起作用吗?

通过执行以下操作使其工作:

  • fonts按需资源标签标记Kanit-Regular数据资产(标签名称可以是您偏好的名称,fonts只是示例)。
  • fonts 标签放入 Initial Install Tags 预取资源标签部分

  • Signing & Capabilities中添加Fonts能力并勾选其中的所有方框

  • 在注册字体之前实现捆绑资源访问请求

像这样:

func registerFont() {
    var cfBundle: CFBundle?
    var resourceRequest: NSBundleResourceRequest?
    if let bundle = Bundle(for: type(of: self)) {
        resourceRequest = NSBundleResourceRequest(tags: Set(arrayLiteral: "fonts"), bundle: bundle)
        cfBundle = CFBundleCreate(kCFAllocatorDefault, bundle.bundleURL as CFURL)
    }
    resourceRequest?.beginAccessingResources() { error in
        if let error = error {
            print(error)
        } else {
            CTFontManagerRegisterFontsWithAssetNames(["Kanit-Regular"] as CFArray, cfBundle, .persistent, true) { (errors, done) -> Bool in
                print(errors)
                return done
            }
        }
    }
}

结果

当范围作为 .persistent.user 传递时,在初始调用 CTFontManagerRegisterFontsWithAssetNames 函数时,用户将被要求将字体安装到系统中,这不是我真正想要的需要。如果范围是 .process.none,将返回与问题末尾提供的相同的 errors 输出。

虽然这个功能不符合我的需求,但我至少验证了它是有效的。也许有人会觉得有用。