从 Android 15 开始,可变字体会在运行时呈现,并且效率和精细度更高。在此更新中,供应商必须将新的可变字体配置添加到 font_fallback.xml
,而不是 fonts.xml
,因为 fonts.xml
已被废弃。如需了解详情,请参阅对可变字体的支持。
在 Android 11 及更低版本中,更新 AOSP 中设备已安装的字体文件(位于 /system/fonts
分区中)或供应商分区中设备已安装的字体文件(位于 /product/fonts
或 /system/fonts
分区中)需要由原始设备制造商 (OEM) 进行系统更新。此要求对表情符号的兼容性具有重大影响。在 Android 12 中,借助 FontManager
系统服务,您可以管理已安装的字体文件,并且无需进行系统更新即可更新设备已安装的字体文件。
Android 12 中存在三个进程的交互:FontManagerService
、Font Updater
和 Application
。
FontManagerService
是系统服务器中的中央管理系统。FontManagerService
存储着每位用户的最新系统字体设置。
FontUpdater
是受 signature|privileged
权限检查信任的可插入字体更新程序。FontUpdater
会与 FontManagerService
通信,以获取、安装、移除或更新当前系统字体设置。FontUpdater
可以通过进程间通信 (IPC) 机制传递新字体文件的内容。FontManagerService
将内容保存到全局可读的存储位置,例如 /data/fonts
文件中。此存储空间受到保护,只能由 FontManagerService
通过 SELinux 政策对其执行写入操作。
当 Application
类启动时,它会将系统字体设置作为 bindApplication
方法的参数传递;然后,它会初始化字体设置,供应用进程使用。
对可变字体的支持
从 Android 15 开始,可变字体配置在 font_fallback.xml
中使用以下格式指定:
<family lang="und-Ethi" supportedAxes="wght,ital">
<font>NotoSansEthiopic-VF.ttf</font>
</family>
在此格式中,可变字体具有静态字体的所有属性,并额外包含一个 supportedAxes
属性。supportedAxes
属性是支持的轴标记的逗号分隔列表。在 Android 15 中,只能指定 wght
和 ital
轴。
如果未指定 supportedAxes
属性,font
节点将作为使用 axis
子项指定的可变字体单个实例的静态字体。
如果指定了 supportedAxes
属性,系统会在运行时为给定的粗细和样式值动态创建字体实例。
开发者可以使用 android.graphics.fonts.SystemFonts#getAvailableFonts
Java API 或 ASystemFontIterator_open
NDK API 获取系统安装的字体文件列表。如需了解支持此更新的开发者 API,请参阅改进的 OpenType 可变字体 API 和 buildVariableFamily
。
自定义字体
有些 OEM 会在 AOSP 中安装或替换字体文件以展示自己的品牌。Android 12 支持此功能,但增加了保持更新设备中的表情符号字体的要求。不修改或不更新表情符号字体文件的 OEM 无需使用此功能。
Google 会更新字体文件,尤其是通过 GMS Core 更新 NotoColorEmoji
文件,因此请不要修改或移除 /system
分区中的 NotoColorEmoji.ttf
文件,也不要从 /frameworks/base/data/fonts/fonts.xml
移除该文件。请注意,您可以通过以下三种方式自定义字体:
- 将
NotoColorEmoji.ttf
文件替换为 OEM 品牌的表情符号字体。 - 根据当地市场的需求修改
NotoColorEmoji.ttf
文件。 - 替换或修改其他字体文件。
如果不打算在 AOSP 中修改表情符号字体,就无需执行任何操作。如果要自定义表情符号字体,请按照以下几部分的说明操作。
将 NotoColorEmoji.ttf 替换为 OEM 品牌的表情符号字体
如需将 NotoColorEmoji.ttf
文件替换为 OEM 品牌的表情符号字体文件,请将表情符号字体放在后备字体链的前面:
- 将您自己的字体(名为
OEMCustomEmoji.ttf
)放到/system
分区中。 修改
/frameworks/base/data/fonts/fonts.xml
(以及 Android 15 及更高版本中的/frameworks/base/data/fonts/font-fallback.xml
),如以下代码所示:<family lang="ko"> <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font> </family> <!-- ADD FOLLOWING LINE --> <family lang="und-Zsye"> <font weight="400" style="normal">OEMCustomEmoji.ttf</font> </family> <!-- END OF MODIFICATION --> <family lang="und-Zsye"> <font weight="400" style="normal">NotoColorEmoji.ttf</font> </family> <family lang="und-Zsym"> <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font> </family>
根据当地市场的需求修改 NotoColorEmoji.ttf
请按照以下步骤,根据当地市场的需求进行自定义:
- 使用其他名称创建您自己的
NotoColorEmoji
文件;例如,将其命名为Modified\_NotoColorEmoji.ttf
。 - 将该文件放在原始
NotoColorEmoji.ttf
文件的前面。
当您执行完第 2 步之后,系统将显示 Modified\NotoColorEmoji.ttf
支持的修改后的字形,而不是原始 NotoColorEmoji.ttf
支持的字形。Google 的建议如下:
- 仅包含此字体中必需的字形。
- 将未经修改的字形委托给原始
NotoColorEmoji.ttf
文件,以便设备接收未来表情符号版本中做出的任何设计修正。
移除字形:如需从 NotoColorEmoji.ttf
文件中移除字形,请按照第 1 步和第 2 步操作,并在 cmap 中指定 glyph ID = 0
。
使用地区标志:如果目标字形是地区标志,请将字形 ID 指定为未知的国家/地区代码。(请使用 country code = "ZZ"
。)
指定 tofu 字形:如果想使用 tofu 字形,可以明确指定 tofu 字形 ID。如果指定 glyphID = 0
,相关应用会将其解读为“字形不可用”。例如,使用此属性时,Paint#hasGlyph
应用会返回 false
。
替换或修改其他字体文件
如需替换或修改其他字体,自定义过程与根据当地市场的需求修改 TTF 文件类似。AOSP 中在运行时更新的未知字体文件会被忽略,也不会更新。Google 会忽略您的设备中的未知字体,包括在 AOSP 中的原始字体基础上修改过的字体文件。
虽然字体更新由 Google 在 GMS Core 中完成,但常规字体更新机制面向所有 OEM 开放。OEM 可以按照满足前提条件、为字体文件签名和进行运行时字体更新部分所述的步骤,安装其他字体更新程序。
满足前提条件
字体更新机制使用 fs-verity
Linux 内核功能。验证您的设备是否符合 fs-verity
的要求,并在设备中添加证书。
为字体文件签名
由于字体文件是存在风险的资源,因此必须通过可信的密钥对其进行验证。请仔细检查所有要更新的字体文件,然后使用您的私钥对其签名。此签名必须符合 fs-verity
的要求。
进行运行时字体更新
字体更新由 FontManager
系统应用执行。FontManager
应用提供最新的已安装系统字体状态,以及使用签名更新字体文件的功能。如需调用更新应用,请将 UPDATE_FONT signature|privileged
权限添加到应用许可名单和清单中。
为应用的更新程序函数提供 UPDATE_FONT signature|privileged
权限。