Windows 下 Compose Multiplatform 中文乱码的 3 条修复路径
【免费下载链接】compose-multiplatformCompose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.项目地址: https://gitcode.com/GitHub_Trending/co/compose-multiplatform
窗口一打开,中文全是豆腐块。Compose Multiplatform 桌面端在 Windows 上遇到中文显示问题并不新鲜:正文变方框、中英文字号对不齐、emoji 直接消失。本文按优先级给出 3 条修复路径,改完即可验收。
默认字体为什么装不下中文
先说结论:豆腐块是缺字形,不是渲染器坏了。
桌面端内置 Roboto 作为默认字体,字库只有拉丁字符,汉字一个都没有。缺字后渲染层沿回退链去系统里找字;链断了,Skia 就用方框占位符顶上。
- Roboto 无中文字形:汉字在默认字体里查不到,直接缺字。
- 回退链依赖系统环境:干净虚拟机、精简镜像上,回退命中不稳定。
- 回退字体度量不同:命中系统字体后,字号、行高也会和英文对不齐。
emoji 走同一条链:Roboto 不含 emoji 字形,回退链没接住就整段消失。
三条修复路径,怎么选
先给答案:正式发行选嵌入字体;体积敏感选系统字体;两者叠加就是运行时回退链。
| 方案 | 兼容性 | 包体积 | 维护成本 | 适用场景 |
|---|---|---|---|---|
| 嵌入中文字体 | 高,不依赖系统环境 | 大:全量 OTF 约 15–20MB,子集后 5MB 内可控 | 低:一次打包长期有效 | 对外分发、多机器一致 |
| 读取系统已装字体 | 中,依赖目标机装了字体 | 零增量 | 中:需按环境回归 | 内网部署、体积敏感 |
| 运行时参数与回退配置 | 中,依赖回退链命中 | 零增量 | 中:参数与框架版本耦合 | 与前两者组合使用 |
三选一不是铁律。生产项目常见组合是"嵌入为主、系统兜底",下面按这个优先级展开。
按优先级落地三种字体方案
先说结论:嵌入 > 系统字体 > 运行时参数,按这个顺序改,回滚成本最低。
嵌入思源黑体的最小配置
适合任何对外分发的应用,改动只在两处:资源目录加文件、主题加一行。
这段代码把思源黑体两个字重注册成全局字体族。
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import org.jetbrains.compose.resources.font // 字体文件放入 commonMain/composeResources/font/ val CnFontFamily = FontFamily( Font(font.SourceHanSansCNRegular), Font(font.SourceHanSansCNBold, FontWeight.Bold) ) // 主题挂一行:typography = typography.defaultFontFamily(CnFontFamily)常规与粗体要成对提供,避免加粗走伪渲染;全量字库过大就先做子集再打包。
系统字体回退写法
适合不增加包体、目标机都是标准 Windows 的场景,按字体注册名逐级回退。
这段代码按名称构造系统字体回退链,无需任何资源文件。
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.SystemFont // 按系统字体注册名回退:先雅黑,再宋体 val WinFontFamily = FontFamily( SystemFont("Microsoft YaHei"), SystemFont("SimSun") ) // 同样用 defaultFontFamily(WinFontFamily) 挂到主题字体名写错不会报错,只会静默跳到下一项;验收时逐字核对注册名。
运行时参数与回退链配置
适合不想动资源、只调字体查找顺序的场景,通常作为前两种方案的安全网。
这段代码在启动阶段指定回退顺序,不改动任何字体资源。
fun main() { // JVM 属性:指定 Skiko 回退字体顺序 System.setProperty( "compose.font.fallback", "Microsoft YaHei,SimSun" ) application { Window(onCloseRequest = ::exitApplication) { App() } } }preloadFont 预加载自 1.8.0 引入,主要服务 Web 目标;桌面端真正生效的是 1.7.0 起的字体缓存,Font 复用时不再反复读原始字节。
验收清单:症状、原因、动作
先给答案:对号入座,十分钟定位九成问题。
- 中文是方框、英文正常 → 嵌入字体没被加载 → 确认 res.font 生成的访问器指向真实文件,常见错是路径少写一级目录。
- 中英文字号对不齐 → 回退字体度量与 Roboto 不一致 → 全量文本走同一个 defaultFontFamily,别在局部 Text 单独换字族。
- 包体明显变大 → 全量中文字体太大 → 用字体子集工具裁剪常用字再打包,目标压到 5MB 内。
- 改了字体却不生效 → 命中了旧缓存 → 1.7.0 起有字体缓存机制,改资源后清构建产物重新编译。
- emoji 整段消失 → 回退链不含 emoji 字形 → 嵌入 Noto Color Emoji,或把系统 Segoe UI Emoji 加进回退链。
- 生僻字变框 → 字库覆盖不全 → 换全字库版本,子集裁剪时把生僻字、竖排标点一并纳入。
收尾:怎么定,看什么
决策一句话:能接受 5MB 就上嵌入字体,其余场景用系统字体回退链兜底。 版本提醒:CHANGELOG.md 记录了字体能力的时间线——1.6.0 引入 SystemFont、1.7.0 加入字体缓存、1.8.0 提供 preloadFont,升级框架时顺手核对一遍再上生产。
【免费下载链接】compose-multiplatformCompose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.项目地址: https://gitcode.com/GitHub_Trending/co/compose-multiplatform
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考