Android 12下PdfView.createWebPrintJob导出PDF常规字重字体显示异常
问题描述
- 调用
PdfView.createWebPrintJob接口将WebView内容转换为PDF时,转换流程可正常执行,但导出文件存在字体样式加载异常 - 加载Google Noto Serif自定义字体时,仅设置
font-weight: bold或字重数值≥600的文本可正常显示,常规字重内容显示异常 - 测试页面直接在WebView中加载预览时,所有字重的自定义字体均无显示问题
- 异常仅出现在Android 12系统设备上,Android 10设备测试相同流程无复现
复现代码
<html> <head> <style type="text/css"> @font-face { font-family: 'Noto'; font-style: normal; src: url('NotoSerif-Regular.ttf'); } p.normal { font-family: 'Noto'; font-size:14px; } p.bold { font-family: 'Noto'; font-size:18px; font-weight: bold; } p.large{ font-family: 'Noto'; font-weight: 600; font-size:18px; } </style> </head> <body> <p class="normal">Normal - not working</p> <p class="bold">Bold - working</p> <p class="large">W600 - working</p> </body> </html>
问题根因
该异常是Android 12系统WebView打印管线的已知逻辑变更导致:
- Android 12搭载的WebView基于Chromium 90+版本,打印生成PDF的渲染管线中,对未显式声明
font-weight属性的@font-face规则,会默认将该字体的匹配阈值设置为600:仅当文本设置的字重≥600时,才会匹配引用的自定义字体文件;字重<600的常规文本会错误匹配系统兜底字体,且该兜底字体未被正确嵌入PDF文件,最终导致常规字重内容在绝大多数PDF阅读器中渲染失败 - WebView直接预览页面走的是常规渲染管线,不受打印管线的字重默认匹配规则影响,因此预览时字体显示正常;Android 10及更早版本的WebView打印管线无该默认阈值逻辑,因此不会复现该问题
解决方案
- 显式声明
@font-face对应的字重属性
在自定义字体的@font-face规则中补全font-weight声明,明确指定字体文件对应的字重值,规避打印管线的默认阈值匹配逻辑。修改后的常规字重字体声明如下:
如果页面需要使用粗体字重,需额外引入对应粗体版本的字体文件,单独声明对应@font-face { font-family: 'Noto'; font-style: normal; font-weight: 400; /* 显式声明该字体对应常规字重 */ src: url('NotoSerif-Regular.ttf'); }font-weight: 700的@font-face规则,不要依赖引擎对常规字体做伪粗体转换,避免PDF字体嵌入异常。 - 禁用打印场景字体子集化(可选兜底方案)
如果补全字重声明后仍存在渲染异常,可在HTML的<head>标签中加入如下meta标签,禁用WebView打印时的字体子集裁剪逻辑,避免常规字重的字体片段被错误丢弃:<meta name="webkit-print-font-subset" content="disable"> - 字体加载完成后再触发打印任务
调用createWebPrintJob前,先等待页面自定义字体全部加载完成,避免打印管线初始化时字体资源未完成加载导致的匹配异常,Kotlin示例代码如下:webView.evaluateJavascript( """ (function() { return document.fonts.ready; })(); """.trimIndent() ) { // 字体加载完成后再执行PDF打印布局、生成逻辑 }
内容的提问来源于stack exchange,提问作者Angelhia de Fiesta
相关产品推荐
相关产品推荐

