iOS CoreText通过CTFontManagerRegisterGraphicsFont获取注册字体列表

Pra*_*y C 5 fonts uifont core-text ios

我通过以下方式动态注册字体:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{

    if ([url isFileURL])
    {
        // Handle file being passed in
        NSLog(@"handleOpenURL: %@",url.absoluteString);


        NSData *inData = [NSData dataWithContentsOfURL:url];
        CFErrorRef error;
        CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
        CGFontRef fontRef = CGFontCreateWithDataProvider(provider);

        UIFont *font;
        if (!CTFontManagerRegisterGraphicsFont(fontRef, &error)) {
            CFStringRef errorDescription = CFErrorCopyDescription(error);
            NSLog(@"Failed to load font: %@", error);
            CFRelease(errorDescription);
        } else {
            CFStringRef fontNameRef = CGFontCopyPostScriptName(fontRef);
            NSLog(@"fontNameRef: %@",fontNameRef);
            font = [UIFont fontWithName:(__bridge NSString *)fontNameRef size:80];
            [self.arrayOfFonts addObject:(__bridge NSString *)fontNameRef];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshFont" object:nil];
            CFRelease(fontNameRef);
        }
        CFRelease(fontRef);
        CFRelease(provider);
        return YES;
    }
    else
    {
        return NO;
    }
}
Run Code Online (Sandbox Code Playgroud)

第一次使用效果很好。看来,如果我关闭应用程序并尝试再次注册相同的字体,则会出现(预期的)错误"Failed to load font: Error Domain=com.apple.CoreText.CTFontManagerErrorDomain Code=105 "Could not register the CGFont '<CGFont (0x1c00f5980): NeuropolXRg-Regular>'" UserInfo={NSDescription=Could not register the CGFont '<CGFont (0x1c00f5980): NeuropolXRg-Regular>', CTFailedCGFont=<CGFont (0x1c00f5980): NeuropolXRg-Regular>}"

这似乎是因为字体已经注册了。的文档CTFontManagerRegisterGraphicsFont指出:

“使用字体管理器注册指定的图形字体。可以通过字体描述符匹配发现已注册的字体。尝试注册已注册的字体或包含与已注册字体相同的 PostScript 名称的字体将会失败。”

究竟如何做到“通过字体描述符匹配”?

如何获取已通过该CTFontManagerRegisterGraphicsFont方法注册的所有字体的列表,以便我可以在再次注册之前取消注册它们?

编辑:

我尝试过使用CTFontManagerCopyAvailablePostScriptNamesCTFontManagerCopyAvailableFontFamilyNames方法,但两者都只打印出 iOS 上已有的字体名称。不是我注册的CTFontManagerRegisterGraphicsFont

注意:我并不是询问 iOS 上已有的字体,这些字体可以通过迭代 [UIFont familyNames] 来列出。

Pra*_*y C 3

我向 Apple DTS(开发者技术支持)记录了一张票,他们说:

\n\n

“您需要自己跟踪使用CTFontManagerRegisterGraphicsFont注册的字体。CTFontManagerRegisterGraphicsFont返回的错误代码kCTFontManagerErrorAlreadyRegistered会告诉您是否已经注册了字体。使用字体描述符匹配来发现您的字体是否已安装可能是\xe2\ x80\x99t 是一个好方法,因为系统可能会选择对丢失的字体执行字体替换。使用 CTFontManagerRegisterGraphicsFont 安装字体只是使其可供您的 app\xe2\x80\x99s 使用。它不是用于发现已安装字体的查询服务如果这还不足以满足您的偏好,那么我认为您最好考虑提交功能请求,询问您希望获得的功能。”

\n\n

所以基本上,我们需要跟踪我们自己注册的字体。

\n\n

我最终使用的解决方案/解决方法:

\n\n

Action Sheet\'s目前,我的应用程序允许用户使用字体文件上的“复制到 MYAPP”按钮添加字体。同样的解决方案也适用于我从服务器下载的字体文件。

\n\n

.ttf为了使我的应用程序在和文件的操作表中列出.otf,在我的应用程序的 info.plist 中,我添加了一个新的文档类型:

\n\n
    <key>CFBundleDocumentTypes</key>\n    <array>\n        <dict>\n            <key>CFBundleTypeIconFiles</key>\n            <array/>\n            <key>CFBundleTypeName</key>\n            <string>Font</string>\n            <key>LSItemContentTypes</key>\n            <array>\n                <string>public.opentype-font</string>\n                <string>public.truetype-ttf-font</string>\n            </array>\n        </dict>\n    </array>\n
Run Code Online (Sandbox Code Playgroud)\n\n

这允许我的应用程序显示在action sheet任何字体文件中。因此,用户可以将字体文件放在 Dropbox、Google Drive 或任何其他文件共享应用程序上。然后他们可以将字体从那里导入到我的应用程序中。导入后,我需要将字体文件从临时tmp inbox文件夹移动到我的应用程序Documents fonts目录。该fonts目录保留所有自定义字体。之后,我注册此自定义字体并将名称添加到self.arrayOfFonts数组中。这是包含我所有字体列表的数组。

\n\n

而且似乎CTFontManagerRegisterGraphicsFont仅适用于会话。因此,当应用程序从应用程序切换器关闭并重新启动时,该字体将不再注册。因此,每次启动后,我都会检查documents/fonts文件夹并重新注册所有字体并将它们的名称添加到数组中self.arrayOfFonts

\n\n

我的应用程序代码的其余部分可以使其正常工作:

\n\n
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{\n\n    if ([url isFileURL])\n    {\n        // Handle file being passed in\n        NSLog(@"handleOpenURL: %@, extension: %@",url.absoluteString,url.pathExtension);\n        [self moveFontFrom:url];\n        return YES;\n    }\n    else\n    {\n        return NO;\n    }\n}\n\n-(void)moveFontFrom:(NSURL*)fromurl{\n    NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingPathComponent:@"fonts"];\n    // New Folder is your folder name\n    NSError *error1 = nil;\n    if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath]){\n        [[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error1];\n    }\n    NSLog(@"error1: %@", error1.debugDescription);\n    NSURL *tourl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",stringPath,[[fromurl absoluteString] lastPathComponent]] isDirectory:NO];\n\n    NSLog(@"Trying to move from:\\n\\n%@\\n\\nto:\\n\\n%@\\n\\n", fromurl.absoluteString,tourl.absoluteString);\n\n    NSError* error2;\n    if ([[NSFileManager defaultManager] fileExistsAtPath:tourl.path]){\n        [[NSFileManager defaultManager] removeItemAtPath:tourl.path error:&error2];\n        NSLog(@"Deleting old existing file at %@ error2: %@", tourl.path,error2.debugDescription);\n    }\n\n\n    NSError* error3;\n    [[NSFileManager defaultManager] moveItemAtURL:fromurl toURL:tourl error:&error3];\n    NSLog(@"error3: %@", error3.debugDescription);\n\n    if (!error3) {\n        NSString *fontName = [self registerFont:tourl checkIfNotify:YES];\n        if (fontName) {\n            if (![self.arrayOfFonts containsObject:fontName]) {\n                [self.arrayOfFonts addObject:fontName];\n                [self.arrayOfFonts sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];\n                [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshFont" object:nil userInfo:@{@"font":fontName}];\n            }\n        }\n    }\n}\n\n-(void)startupLoadFontsInDocuments{\n\n    self.arrayOfFonts = [NSMutableArray new];\n    NSString *location = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingPathComponent:@"fonts"];\n    NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:location error:NULL];\n    for (NSInteger count = 0; count < [directoryContent count]; count++)\n    {\n        NSLog(@"File %ld: %@/%@", (count + 1), location,[directoryContent objectAtIndex:count]);\n        NSString *fontName = [self registerFont:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",location,[directoryContent objectAtIndex:count]] isDirectory:NO] checkIfNotify:NO];\n        if (fontName) {\n            if (![self.arrayOfFonts containsObject:fontName]) {\n                [self.arrayOfFonts addObject:fontName];\n            }\n        }\n    }\n    [self.arrayOfFonts sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];\n}\n\n-(NSString*)registerFont:(NSURL *)url checkIfNotify:(BOOL)checkIfNotify{\n    NSData *inData = [NSData dataWithContentsOfURL:url];\n    CFErrorRef registererror;\n    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);\n    CGFontRef fontRef = CGFontCreateWithDataProvider(provider);\n    NSString *fontName = (__bridge NSString *)CGFontCopyPostScriptName(fontRef);\n    BOOL registerFontStatus = CTFontManagerRegisterGraphicsFont(fontRef, &registererror);\n    if (!registerFontStatus) {\n        CFStringRef errorDescription = CFErrorCopyDescription(registererror);\n        NSError *registererr = (__bridge NSError*)registererror;\n        if ([registererr code]==kCTFontManagerErrorAlreadyRegistered) {\n            NSLog(@"Font is already registered!");\n        }\n        NSLog(@"Failed to load font: %@", registererror);\n        CFRelease(errorDescription);\n\n        /*CFErrorRef unregistererror;\n    BOOL unregisterFont = CTFontManagerUnregisterGraphicsFont(fontRef, &unregistererror);\n    NSLog(@"Font unregister status: %d",unregisterFont);\n    CFStringRef unregistererrorDescription = CFErrorCopyDescription(unregistererror);\n    NSError *unregistererr = (__bridge NSError*)unregistererror;\n    NSInteger code = [unregistererr code];\n\n    NSLog(@"Failed to unregister font: %@", unregistererr);\n    CFRelease(unregistererrorDescription);*/\n\n        if (checkIfNotify) {\n            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Already added" message:@"That font is already added to the app. Please select it from the fonts list." preferredStyle:UIAlertControllerStyleAlert];\n            [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {\n\n            }]];\n            [[self.window rootViewController] presentViewController:alert animated:YES completion:nil];\n        }\n    } else {\n        CFStringRef fontNameRef = CGFontCopyPostScriptName(fontRef);\n        fontName = (__bridge NSString*)fontNameRef;\n        CFRelease(fontNameRef);\n\n        NSLog(@"fontName: %@",fontName);\n    }\n    CFRelease(fontRef);\n    CFRelease(provider);\n    return fontName;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意:正如您所注意到的,我已经注释掉了CTFontManagerUnregisterGraphicsFont. 用于取消注册字体的方法CTFontManagerUnregisterGraphicsFont似乎对我不起作用,因为它给出了一个错误,指出字体正在使用中,因此无法取消注册。因此,当我需要删除字体时,我只需将其从self.arrayOfFonts数组和documents/fonts文件夹中删除即可。

\n