知道自己的答案和这篇答案撞车了,印象中知乎还有一篇写得相当详细的答案,但是我找不到了。我一直想把“如何评价思源黑体 (Source Han Sans) 字族?”过于冗长的部分独立出来,同时也想为自己折腾的历程做个总结,所以又写了这篇答案。
适用于 Android 5.x 以上,基于思源黑体 1.004 版本:
背景:
Google 已经将 Noto Sans CJK(思源黑体的 Google 版)作为 Android 5.0 以后的系统字体。(刚发布时,Adobe 说这是一款用于桌面的字体……[1])然而由于系统安装包的体积有限,Google 只在系统中内置了简、繁、日、韩 4 个高度子集化的字体,应该是只保留了相应地区与其他地区字形不同的字,日文假名依然使用 4.x 时代的 MTLmr3m.ttf(因为这 4 个字体都不含假名),而且只提供了一个字重。某些厂商(如 Motorola、Sony)更是将这些字体删除,仅使用古老的 Droid Sans Fallback。(索尼罪大滔天!)因此,要想获得 Android 5.x 的终极字体体验,还是需要折腾一番。
在操作之前,请先通读教程,手机要获得 Root 权限或者能进入 Recovery,需要掌握相应的 Android 和 Linux 知识。如果你不清楚每一步是在做什么和可能导致的后果,请不要操作。
先上效果
左:只使用 Regular,右:加入 Medium 与 Light
左:伪粗体,右:加入 Bold
(伪粗体会有较多的笔画粘连,边缘比较模糊,实机显示效果差别更大。)
1. 将需要的字体复制到 /system/fonts 目录下,我推荐 Region-specific Subset OTF 版,在这里可以获得。由于 Android 现在拥有了新的 OTF 渲染引擎,因此无需将 otf 改名 ttf,更不需要用字体编辑软件。比如(我没有韩文需求,所以这里没有列韩文版,下同):
SourceHanSansCN-Light.otf
SourceHanSansCN-Regular.otf
SourceHanSansCN-Medium.otf
SourceHanSansCN-Bold.otf
SourceHanSansTW-Light.otf
SourceHanSansTW-Regular.otf
SourceHanSansTW-Bold.otf
SourceHanSansJP-Light.otf
SourceHanSansJP-Regular.otf
SourceHanSansJP-Bold.otf一共增加了 61.3MB,比系统自带的 15.5 MB 要大不少。
注释:为什么要有 Medium?
按照 Google 官方 Material Design 指南 Styles 一节[2],Light 字重只用于最大的 Display 4 样式,而 Medium 广泛应用在小标题和按钮上,缺席的却是 Bold。可能是由于 Google 认为 Bold 对于 UI 字体来说太粗了,这一点在这一节的后半部分关于 Tall Script(南亚、东南亚语言)的解释中可以推测出来。
(Medium 字重和高亮色一起构成了“这个元素可以点击”这样的暗示。)
随着扁平化的潮流,iOS 的 UI 中 Medium 字重也广泛应用在标题上[3]:
(在系统 UI 中,你基本见不到 Bold 的身影。)
不幸的是,Android 发行版实际上只为 CJK 提供了一个字重,比 Tall Script 的两个字重还要少,Google 官方却厚颜无耻地说 Noto Sans CJK 有七种字重,所以可以和英文使用一样的字重设置……因此,当开发者使用 Medium 的时候,我们看到的是 Regular,而 Android 系统也不会像 Bold 那样自动加粗生成一个伪粗体,这种字体的微妙差别完全无法体现。
因此我的建议是为自己 UI 常用的语言备齐 4 个字重(Light、Regular、Medium、Bold),而对于其他的语言,备齐 3 个。这是因为在网页和文档中 Bold 还在广泛使用(为了做出强烈的对比),Light 也在一些网页设计中占有非常重要的地位(CSS 就提供 font-weight: lighter),甚至到了滥用的程度。
2. 编辑 /system/etc/fonts.xml,将(Android 5.x)
NotoSansHans-Regular.otf
NotoSansHant-Regular.otf
NotoSansJP-Regular.otf
NotoSansKR-Regular.otf
或者(Android 6.0)
NotoSansSC-Regular.otf
NotoSansTC-Regular.otf
NotoSansJP-Regular.otf
NotoSansKR-Regular.otf
替换为
SourceHanSansCN-Light.otf
SourceHanSansCN-Regular.otf
SourceHanSansCN-Medium.otf
SourceHanSansCN-Bold.otf
SourceHanSansTW-Light.otf
SourceHanSansTW-Regular.otf
SourceHanSansTW-Bold.otf
SourceHanSansJP-Light.otf
SourceHanSansJP-Regular.otf
SourceHanSansJP-Bold.otf
NotoSansKR-Regular.otf
理论上还应该修改为了兼容旧软件而保留的 /system/etc/fallback_fonts.xml,然而实际测试只修改 fonts.xml 没有发现有问题的地方,故此步骤可选,如有需要可以参照下方适用于 4.x 的部分。
3. 修复权限,将以上涉及的所有文件的权限设置为 644 (-rw-r--r--),可以用文件管理器手工操作,也可以使用 adb:
adb shell
su
mount -o rw,remount /system
chgrp 0 /system/etc/fonts.xml
chmod 644 /system/etc/fonts.xml
chgrp 0 /system/fonts/*
chmod 644 /system/fonts/*必须正确修改权限,否则可能会导致字体异常甚至变砖,请做好一切备份。即使按照正确的步骤操作,部分脆弱机型也可能会无限重启或变砖,为了保险可以在 Recovery 下操作。如遇上述情况可以尝试清理缓存和 Dalvik 缓存。(不要问我是怎么知道的,这些都是血与泪换来的。)
4. 重启。
附:Recovery 下全程用 adb 操作的步骤,Windows 系统
首先挂载 /system,然后:
for %i in (*.otf) do adb push %i /system/etc/%~nxi
for %i in (*.xml) do adb push %i /system/etc/%~nxi
adb shell
chmod 644 /system/etc/fonts.xml
chmod 644 /system/fonts/*
reboot
PS:随着 Android 字体技术的进步,缺字、错乱等问题都不复存在了,也不用再考虑 Android 4.x 中的粗体问题。
参考资料
[1] 隆重介绍 思源黑体:一款Pan-CJK 开源字体
[2] https://www.google.com/design/spec/style/typography.html
[3] https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/ColorImagesText.html
-----
注意,在 Android 中修改字体,请务必注意权限问题,否则将导致字体异常甚至变砖。请做好一切备份,如果变砖请进入 Recovery 操作。
我习惯的做法不是替换字体,而是将字体直接复制到 /system/fonts 目录下,然后在 fallback_fonts.xml 的
DroidSansFallback.ttf
前加入
SourceHanSansCN-Regular.otf
SourceHanSansCN-Bold.otf
本来以为这么一做又入改字体的大坑了。但是这次 Android 奇怪的 fallback 机制居然表现得异常完美。
▲ fallback 韩文。
▲ 国际音标,依然那么
销魂 惨不忍睹。(其实是 fallback 到了 Droid Sans Fallback。)
▲ 颜文字,完美。
(这一段主要是对我的这个答案的回应:对比 iOS 系统 Android 的字体渲染有何区别?)
(2) 进阶用法
我已经在 Android 上使用思源黑体半个多月,几乎没有任何兼容性上的问题,而且神奇地避开了 Android 在字体 fallback 和渲染上的一些小 bug [注1],更加坚定了我将其用作主力字体的信心。
Android
自 4.1 以来增加了 fallback 时对不同语言可以采用不同的次序的功能,配合 MTLmr3m.ttf
字体,为日语用户提供了日文汉字字形。于是思源黑体也可以如法炮制:将不同区域的版本拷贝到 /system/fonts 后,在原版的
fallback_fonts.xml 的
DroidSansFallback.ttf
前加入
SourceHanSansCN-Regular.otf
SourceHanSansCN-Bold.otf
SourceHanSansTWHK-Regular.otf
SourceHanSansTWHK-Bold.otf
SourceHanSansTWHK-Regular.otf
SourceHanSansTWHK-Bold.otf
SourceHanSansTWHK-Regular.otf
SourceHanSansTWHK-Bold.otf
再在之后加入
SourceHanSansJP-Regular.otf
SourceHanSansJP-Bold.otf
即可根据语言的不同自动调用相应的地区字形。(我没有安装韩文版。)
说几点问题:
从上面可以看出语言代码是区分大小写的。
只有日语能在切换系统界面语言时切换字形;语言设为繁体依然是简体字形,然而在网页中却可以。
系统语言设为日语时显示简体中文会缺字,无法正确 fallback。[注2]
繁体版的逗号太高了,明显高于居中的位置。
网页中有行距问题,参考下图:
(3) 粗体问题
这么做本来是没有问题的,但是万恶的 Adobe 把 1.001 版的粗体的信息除 Preferred Family
之外有关粗体的内容都改为了常规体(其实这是为了解决一些bug,比如[3])。加上 Android
奇怪的字体机制,发现一个常规体就会将它用作常规体(说好的严格按照 XML 顺序呢!),因此用 1.001 版的思源黑体直接按照上面的步骤操作完后会带来满屏粗体的情况。(感谢 @Shin li 、 @翟滢皓 、@黄俊 在原答案的评论)
所以我们要对它做一点小修改。首先去下载 Adobe OpenType 字体开发套件(AFDKO)。主要用到的是 ttx 工具。
首先,将 'head' 'OS/2' 和 'name' 表提取出来。
ttx -t "head" -t "OS/2" -t "name" SourceHanSansCN-Bold.otf
将 1.001 版和 1.000 版的表都提取出来后,用软件进行对比。把其中关于“Bold”(粗体)的内容都改好,把 fsType、fsSelection 和 macStyle 这几个 flag 也改过来。
或是按照下面的 diff 改(行号不一定相同)。
18c18
<
--->
30c30
<
--->
59c59
<
--->
84c84
< Regular
---> Bold
132c132
< Regular
---> Bold
177c177
< Regular
---> Bold
修改完毕后,将它们合并回原字体
ttx -m SourceHanSansCN-Bold.otf SourceHanSansCN-Bold.ttx
大功告成!接下来如法炮制繁体、日文等就可以了!全部修改完成后,按照(1)(2)中的步骤安装就可以了。
(4) 结论
综上,我可以毫不夸张地说这是我目前遇到的 Android 修改最方便的高质量中文字体。而且最重要的是没有那些“合成字体”的版权问题。
强烈推荐每一个对字体有要求的 Android 用户替换!注释
[注1] 其实在非网页环境下 fallback 是有一定问题的,比如知乎客户端的列表中,若涉及国际音标则无法显示,然而点开答案后音标正常,应该是答案界面使用了 WebView 所致。
[注2] 这是另一个问题,应该能通过安装 思源黑体 (Source Han Sans) 的各个版本有什么不同?
里提到的那个未正式发布的各地区字形)的全字数版本解决,不过这只是权宜之计,因为根本原因还是 Android 的 fallback
问题。(注:1.001 版已包括这个版本,OTF[不是Subset OTF]版即是。然而,它在 Android
上的兼容性竟远不如 Subset OTF版。)