Compose/Wasm支持中文显示
Compose很好玩,但他的Wasm编译目标默认是无法显示中文的,怎么解决呢?
誓要救安卓开发于水火的Compose框架,有跨平台支持,能跑在桌面上,甚至跑在Web上(via Wasm)。这令我十分振奋,因为我不必学习另一门语言和技术就能让自己的Demo跑在浏览器上,分享一个链接就能让我的小伙伴体验,而不需要他安装JVM了。
尽管Compose/Wasm的支持还在alpha阶段,且因为依赖Wasm gc特性只能跑在较新的Chrome/Firefox浏览器上,还是很令人期待。
创建一个Compose/Wasm项目
最方便的办法是使用 Kotlin Multiplatform Wizard 。勾选需要的目标平台,直接生成和下载工程。
使用wasmJsBrowserRun任务可以编译并在浏览器预览效果,而使用wasmJsBrowserDistribution可以打包和发布应用。
我借助Compose/Wasm写了个简单的俄罗斯方块,可见在合适场景下还是值得期待的。
支持中文显示
修改按钮文本使其包含中文,可见中文没有正常显示出来,只显示了占位符。
这个问题在YouTrack上已经有人在跟进,而记录显示上周版本1.7.0解决了这个问题。因此,首先尝试升级Compose版本,问题依旧。
于是一番查找找到了原始解决问题的PR,参照其中写法修改顺利显示了汉字,以下步骤:
准备一个中文字体,如资源圆体,复制到资源目录下。
修改代码加载字体
private const val resourceHanTTF = "./ResourceHanRoundedCN-Regular.ttf"
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
ComposeViewport(document.body!!) {
val fontFamilyResolver = LocalFontFamilyResolver.current
val fontsLoaded = remember { mutableStateOf(false) }
if (fontsLoaded.value) {
App()
} else {
Text("Loading Fonts...")
}
LaunchedEffect(Unit) {
val fontBytes = loadRes(resourceHanTTF).toByteArray()
val fontFamily = FontFamily(listOf(Font("ResourceHanRounded", fontBytes)))
fontFamilyResolver.preload(fontFamily)
fontsLoaded.value = true
}
}
}
suspend fun loadRes(url: String): ArrayBuffer {
return window.fetch(url).await<Response>().arrayBuffer().await()
}
fun ArrayBuffer.toByteArray(): ByteArray {
val source = Int8Array(this, 0, byteLength)
return jsInt8ArrayToKotlinByteArray(source)
}
@JsFun(
""" (src, size, dstAddr) => {
const mem8 = new Int8Array(wasmExports.memory.buffer, dstAddr, size);
mem8.set(src);
}
"""
)
internal external fun jsExportInt8ArrayToWasm(src: Int8Array, size: Int, dstAddr: Int)
internal fun jsInt8ArrayToKotlinByteArray(x: Int8Array): ByteArray {
val size = x.length
@OptIn(UnsafeWasmMemoryApi::class)
return withScopedMemoryAllocator { allocator ->
val memBuffer = allocator.allocate(size)
val dstAddress = memBuffer.address.toInt()
jsExportInt8ArrayToWasm(x, size, dstAddress)
ByteArray(size) { i -> (memBuffer + i).loadByte() }
}
}
问题解决
总结
Compose/Wasm能正常在较新的浏览器运行,开发也不算困难,但由于其自渲染的技术原理,SEO极其不友好。由于浏览器没有统一的获取本地字体API,我们不得不加载远程字体以支持中文。一个完整的中文字体包可能超过10M,实际使用时可能先进行裁剪。
最后修改于 2024-10-25