如何在assets目录CSS中引用res/fonts字体及配置WebView使用该字体?
嘿,这两个问题都是Android WebView里自定义字体的常见场景,我来给你梳理下实操性强的解法:
直接在CSS里写res/fonts的路径是行不通的——WebView对assets和res资源的访问规则完全不一样。这里有两种省心的方案:
方案1:复制字体到assets目录(最推荐)
把res/fonts里的目标字体(比如my_custom_font.ttf)复制到assets下的子文件夹,比如assets/fonts/。然后在assets的CSS里用相对路径直接引用:@font-face { font-family: 'MyCustomFont'; src: url('./fonts/my_custom_font.ttf') format('truetype'); font-weight: normal; font-style: normal; }这种方法零额外配置,WebView能直接解析assets内的相对路径,踩坑概率最低。
方案2:通过Content URI引用res字体
如果不想复制字体文件,可以通过代码生成res字体的可访问URI,再注入到CSS中:- 在Kotlin/Java代码里生成字体的Content URI:
val fontUri = "android.resource://${packageName}/R.font.my_custom_font" - 把这个URI直接写进HTML的style标签(或者通过JS注入),比如:
@font-face { font-family: 'MyCustomFont'; src: url('android.resource://com.your.app.package/R.font.my_custom_font') format('truetype'); }
注意:Android 10+可能需要确保WebView有权限访问这个URI,不过默认情况下是允许的。
- 在Kotlin/Java代码里生成字体的Content URI:
核心思路是让assets里的CSS能拿到res字体的有效访问路径,这里有两种实现方式:
方式1:在HTML中嵌入动态生成的Font Face规则
你可以在代码里生成包含res字体URI的@font-face规则,插入到HTML的中,再引用assets的CSS:- 代码生成字体样式:
String packageName = getPackageName(); String fontUri = "android.resource://" + packageName + "/R.font.my_custom_font"; String fontFaceStyle = "<style>@font-face { font-family: 'MyCustomFont'; src: url('" + fontUri + "') format('truetype'); }</style>"; - 加载HTML时,把这个样式标签和assets的CSS一起引入:
<html> <head> <!-- 动态插入的字体规则 --> <style>@font-face { font-family: 'MyCustomFont'; src: url('android.resource://com.your.app.package/R.font.my_custom_font') format('truetype'); }</style> <!-- 引用assets里的CSS --> <link rel="stylesheet" href="file:///android_asset/styles.css"> </head> <body> <p class="custom-text">使用自定义字体的文本</p> </body> </html>
之后assets的CSS就可以直接用
font-family: 'MyCustomFont';来调用这个字体了,比如:.custom-text { font-family: 'MyCustomFont'; font-size: 16px; }- 代码生成字体样式:
方式2:通过JS注入替换CSS中的字体路径
如果不想修改HTML结构,可以在WebView加载完成后,用JS把assets CSS里的占位路径替换成res字体的URI:- 先开启WebView的JavaScript支持:
webView.settings.javaScriptEnabled = true - 在页面加载完成的回调中注入JS:
webView.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) val fontUri = "android.resource://${packageName}/R.font.my_custom_font" view?.evaluateJavascript(""" // 遍历所有样式表,替换指定字体的路径 Array.from(document.styleSheets).forEach(sheet => { try { Array.from(sheet.cssRules).forEach(rule => { if (rule.type === CSSRule.FONT_FACE_RULE && rule.style.fontFamily === "'MyCustomFont'") { rule.style.src = `url('$fontUri') format('truetype')`; } }); } catch(e) {} // 跨域样式表可能会报错,忽略即可 }); """, null) } } - 此时assets的CSS可以先写一个占位的@font-face:
@font-face { font-family: 'MyCustomFont'; src: url('placeholder.ttf') format('truetype'); /* 占位用的无效路径 */ }
页面加载完成后,JS会自动把占位路径替换成res字体的实际URI。
- 先开启WebView的JavaScript支持:
内容的提问来源于stack exchange,提问作者efor18

