由于kmp在web/wasm目标上的渲染采用的是skia+canvas方案,而不是css+dom,受wasm的沙箱机制所限,skia引擎不能读取到系统的本地字体库,导致中文文本无法正常渲染

官方在Use new skiko API to provide font fallbacks by eymar · Pull Request #1400 · JetBrains/compose-multiplatform-core中给出了修复解决方案。只是其中的这一行代码
val notoEmojisBytes = loadEmojisFontAsBytes() // loadRes(notoColorEmoji).toByteArray()
有点让人困惑。loadRes()这个函数在ide里面调不出来,直接给FontFamilyResovler传递FontFamily(Res.font.NotoSansCJK)又是无效的
不得不吐槽一句,官方文档写的挺烂的,针对web目标加在特定字体这一部分居然放在RTL语言处理章节中,不用搜索谁找得到啊。。。https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-rtl.html#fonts-for-web-targets
这里的文档中的示例
val notoEmojisBytes = loadEmojisFontAsBytes()
val fontFamily = FontFamily(listOf(Font("NotoColorEmoji", notoEmojisBytes)))
fontFamilyResolver.preload(fontFamily)
同样没有给出 loadEmojiFontAsBytes() 的具体实现,呃呃呃
好在底下提了一嘴预加载资源api的相关文档链接,其中的示例代码中提到了 preloadFont()这个函数。经过笔者实验,这个函数是有效的,具体写法参考如下示例:
@OptIn(ExperimentalComposeUiApi::class, ExperimentalResourceApi::class)
fun main() {
ComposeViewport(document.body!!) {
val cjkFont by preloadFont(Res.font.NotoSansCJKsc)
val fontFamilyResolver = LocalFontFamilyResolver.current
var fontLoaded by remember { mutableStateOf(false) }
LaunchedEffect(cjkFont) {
cjkFont?.let {
fontFamilyResolver.preload(FontFamily(it))
fontLoaded = true
}
}
if (fontLoaded) App()
else CircularProgressIndicator()
}
}
kmp官网上吹得天花乱坠,什么已经被多家合作伙伴投入生产环境了,结果八百年过去了现在web目标还是beta阶段,唉,未来可期,jb加油吧