在 WKWebView 中使用自定义字体

Posted

技术标签:

【中文标题】在 WKWebView 中使用自定义字体【英文标题】:Using custom fonts in WKWebView 【发布时间】:2014-11-05 06:27:01 【问题描述】:

我在我的应用程序中使用自定义字体。它们被复制到 bundle 并硬编码到 appName-info.plist。 这种字体在整个应用程序和 UIWebView 中都能完美运行。

我正在加载 htmlString [webView loadHTMLString:htmlString baseURL:nil]; 我在带有 css 的 webView 中使用此字体: fontFamily: fontName

但是当我尝试使用 WkWebView 自定义字体时不起作用。 WkWebView 显示随机的默认字体。

我尝试在基本 url 中使用主包路径加载它,并在 css 中使用 font-face - WkWebView 仍然显示随机字体。

如何使自定义字体在 WKWebView 中工作?

【问题讨论】:

ios 9 中看起来如何? iOS 9中的WKWebView现在可以加载本地文件了,是不是也可以加载字体了? 【参考方案1】:

更新:现在可以使用WKURLSchemeHandler

@interface MySchemeHandler : NSObject <WKURLSchemeHandler>
@end

@implementation MySchemeHandler

- (void)webView:(nonnull WKWebView *)webView startURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask

  NSURL *url = urlSchemeTask.request.URL;
  NSString *mimeType = [NSString stringWithFormat:@"text/%@", url.pathExtension]; //or whatever you need
  NSURLResponse *response = [[NSURLResponse alloc] initWithURL:url MIMEType:mimeType expectedContentLength:-1 textEncodingName:nil];
  [urlSchemeTask didReceiveResponse:response];
  NSData *data = [self getResponseData];
  [urlSchemeTask didReceiveData:data];
  [urlSchemeTask didFinish];

@end

在配置您的 WKWebView 实例时:

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
MySchemeHandler *handler = [[MySchemeHandler alloc] init];
[config setURLSchemeHandler:handler forURLScheme:@"myScheme"];
//now pass the config to your WKWebView

-----旧答案---------

我的猜测是WKWebView 不能再访问特定于应用程序的字体,因为它现在处于单独的进程 (XPC) 中。

我通过在 CSS 中添加带有 @font-face 声明的字体来解决这个问题。请参阅here,了解 MDN 上有关如何执行此操作的详细信息。

例子:

@font-face

  font-family: "MyFontFace";
  src:url('url-to-font.ttf');


//And if you have a font with files with different variants, add this:
@font-face

  font-family: "MyFontFace";
  src:url('url-to-italic-variant.ttf');
  font-style:italic;

但这将引用一个本地文件,WKWebView 无法做到这一点(我假设您已经发现了这一点,因为您正在加载 HTML 字符串而不是本地文件)。根据对this question 的评论,我能够使用GCDWebServer 使我的本地HTML 文件正常工作。在您的应用委托中,根据 GCDWebServer 在 GitHub 上的 wiki 将相关文件添加到您的项目后:

GCDWebServer *server = [[[GCDWebServer alloc]init]autorelease];
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
[server addGETHandlerForBasePath:@"/"
   directoryPath:bundlePath indexFilename:nil
   cacheAge:0 allowRangeRequests:YES];
[server startWithPort:8080 bonjourName:nil];

现在您可以像这样在您的包中引用一个名为 test.html 的 HTML 文件:

NSString *path = @"http://localhost:8080/test.html";
NSURL *url = [NSURL URLWithString:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[myWebView loadRequest:request];

将上述@font-face 声明放入您的HTML 文件中的style 元素中(或者如果您真的只需要加载一个字符串,则放入您的HTML 字符串中),您应该可以开始了。

【讨论】:

我在 WKWebView 中尝试了@font-face,但在设备上运行时它似乎不起作用(iOS 8.4)。虽然在模拟器中工作。尝试将@font-face 与 WOFF、SVG 以及内联为 base64 一起使用。 在 Safari 开发工具中查看它只是说“尝试加载此资源时发生错误”,没有 HTTP 错误代码或任何内容。 font-weight 而不是 font-style 为我工作以支持粗体变体。我希望对某人有所帮助... 我正在使用字符串加载 WKWebView,并从 Documents 文件夹(不是捆绑包)中引用本地文件。使用 WKURLSchemeHandler 对我来说是最好的解决方案。我得到这个工作的唯一其他方法是使用 base64,但在某些情况下我得到了一些很大的减速。 哇!这是什么WKURLSchemeHandler怪物!? @font-face 和我的 WKWebView 配合得很好 [Swift 5 || iOS 14.5]。参考:answer-1、answer-2、answer-3【参考方案2】:

由于我不想为此使用另一个第三方,而且我正在构建 html 字符串本身,所以我采用了使用字体的第一部分,而不是使用远程或本地的 url文件,我将字体转换为base64。

css 看起来像这样:

@font-face 
    font-family: 'FONTFAMILY';
    src: url(data:font/ttf;base64,FONTBASE64) format('truetype');

您可以将 FONTFAMILY 替换为您需要的系列,并将 FONTBASE64 替换为从字体生成的 base 64 字符串。

如果您需要在应用程序中创建 base64 字符串,您可以使用它,只需提供文件名和类型(我也使用它来获取其他文件,因此它更通用,您可以删除 ofType 参数并使用 @ “ttf”):

- (NSString*)getBase64FromFile:(NSString*)fileName ofType:(NSString*)type

    NSString * filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:type];

    // Create NSData object
    NSData *nsdata = [NSData dataWithContentsOfFile:filePath];

    // Get NSString from NSData object in Base64
    NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];

    return base64Encoded;

如果你只想做一次然后保存在某个文件中,你可以使用任何将文件转换为base64的在线网站,例如:http://www.opinionatedgeek.com/dotnet/tools/base64encode/

【讨论】:

这适用于我在常规浏览器中,如果我正在测试 HTML 文件,但是,在 WKWebView 中,它会恢复为默认字体。知道可能出了什么问题吗?我提取了字体的base64值并将其替换在css代码中的适当部分。【参考方案3】:

我遇到了同样的问题,在我的情况下,我可以使用 base64 encodingGCDWebServer 修复它WITHOUT

场景:

WkWebView 加载是通过字符串 html WkWebView 正在使用本地 .css 字体是本地字体并添加到***项目中 在 appName-info.plist 中的 key UIAppFonts / Fonts provided by application 下提供了字体条目(注意:我们需要做这个舞蹈因为 WKWebView 忽略了这个 key,但它仍然是一个声明它是个好主意,以便您可以在本机控件中使用字体)

解决方案:

在顶层.css中添加字体如下

@font-face

    font-family: 'FontFamily';
    src: local('FontFamily'),url('FontFileName.otf') format('opentype');


演示项目:

GitHub Project Link

注意:新的演示应用运行可能需要 2-3 秒,我已经测试了它的长 html 字符串,它与 UIWebView 一样工作,没有滞后。相同的字体在 WKWebView 中可能看起来比 UIWebView 小。

【讨论】:

感谢 GitHub 演示,你救了我的命! 相同的字体在 WKWebView 中看起来比 UIWebView 小一点。如何使字体看起来一样?当我将 UIWebView 更改为 WKWebView 时,字体变小了,如何避免这种变化? 在你的标题中添加这个 非常感谢。而且 github 项目真的很有帮助 非常感谢!这解决了它。感谢您提供示例文件。【参考方案4】:

假设您将字体作为复制到目标包的资源嵌入到应用程序中,您可以通过将 NSURL 作为 baseURL 传递给 WKWebView 对字体的访问权限

NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSURL *bundleUrl = [NSURL fileURLWithPath:bundlePath];
[self.webView loadHTMLString:HTML baseURL:bundleUrl];

并在没有任何前面的路径元素的情况下定义字体 url,这反过来又使 WKWebKit 在 baseURL 之前添加

<style>
  @font-face  font-family: 'Custom Font'; src: url('CustomFont.ttf'); 
  ...
</style>

【讨论】:

如果有多个自定义字体怎么办? 对于其他尝试此操作的人,它可以工作!...但 iOS 字体文件名区分大小写,因此请确保您匹配 .css 中使用的 url 中的字体文件骆驼大小写 :) 此解决方案有效。此外,如果字体系列有版本,在我的情况下是 Ubuntu-R.ttf、Ubuntu-C.tff 等,您需要指定一个 ttf,如:@font-face font-family: 'Ubuntu-R'; src: url('Ubuntu-R.ttf'); 效果很好。谢谢! 感谢您提供合理的解决方案。一个建议:您可以直接创建捆绑 url 而不是使用路径。例如NSURL *bundleURL = [[NSBundle mainBundle] bundleURL]; @HenrikHartz 我有一个问题。将baseURL 设置为主捆绑包会破坏呈现的html 中的所有相对网址吗?因为它会解析到主包 url 而不是真正的 API url。我认为这是一个大问题。【参考方案5】:

这是@Henrik Hartz 的 swift 3 版本的精彩答案:

loadHTMLString(htmlString, baseURL: NSURL.fileURL(withPath: Bundle.main.bundlePath))

【讨论】:

以上是关于在 WKWebView 中使用自定义字体的主要内容,如果未能解决你的问题,请参考以下文章

WKWebView 和动态类型 + 自定义字体

在 Android 中使用自定义字体

自定义字体未显示在字体系列列表中

python中matplotlib自定义设置图像标题使用的字体类型:获取默认的字体族及字体族中对应的字体自定义设置图像标题使用的字体类型

带字体手提箱的iPhone自定义字体

Tailwind/CSS 使用自定义字体