news 2026/4/15 20:15:06

Android 系统默认字体替换方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android 系统默认字体替换方案

Android 系统默认字体替换方案

目标

将 Android 系统默认字体替换为阿里巴巴普惠体(Alibaba PuHuiTi)。

最终方案

通过fonts_customization.xml配合 product 分区预装字体文件,使用new-named-family覆盖系统sans-serif字体族。

文件结构

vendor/[product]/fonts/ ├── Android.mk # 编译规则,将字体文件和配置安装到 product 分区 ├── fonts.mk # 产品级 Makefile,声明需要编译的模块 ├── fonts_customization.xml # 字体定制配置 ├── Alibaba-PuHuiTi-Regular.otf # 常规字重字体文件 └── Alibaba-PuHuiTi-Medium.otf # 中等字重字体文件

安装路径

文件安装到设备的路径
Alibaba-PuHuiTi-Regular.otf/product/fonts/
Alibaba-PuHuiTi-Medium.otf/product/fonts/
fonts_customization.xml/product/etc/

关键配置

1. fonts_customization.xml
<fonts-modificationversion="1"><familycustomizationType="new-named-family"name="sans-serif"><fontweight="400"style="normal">Alibaba-PuHuiTi-Regular.otf</font><fontweight="500"style="normal">Alibaba-PuHuiTi-Medium.otf</font><fontweight="700"style="normal">Alibaba-PuHuiTi-Medium.otf</font><!-- ... 其他字重映射 --></family></fonts-modification>

核心要点:customizationType只能为new-named-family,name必须设为"sans-serif",直接覆盖系统默认字体族。系统的默认字体是在frameworks/base/core/res/res/values/config.xml 中的config_bodyFontFamily中定义的。

2. Android.mk
# Build the rest of font files as prebuilt. # $(1): The source file name in LOCAL_PATH. # It also serves as the module name and the dest file name. define build-one-font-module $(eval include $(CLEAR_VARS))\ $(eval LOCAL_MODULE := $(1))\ $(eval LOCAL_SRC_FILES := $(1))\ $(eval LOCAL_MODULE_CLASS := ETC)\ $(eval LOCAL_MODULE_TAGS := optional)\ $(eval LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/fonts)\ $(eval LOCAL_PRODUCT_MODULE := true) \ $(eval include $(BUILD_PREBUILT)) endef font_src_files := \ Alibaba-PuHuiTi-Regular.otf \ Alibaba-PuHuiTi-Medium.otf $(foreach f, $(font_src_files), $(call build-one-font-module, $(f))) build-one-font-module := font_src_files := include $(CLEAR_VARS) LOCAL_MODULE := fonts_customization.xml LOCAL_MODULE_CLASS := ETC LOCAL_PREBUILT_MODULE_FILE := $(LOCAL_PATH)/fonts_customization.xml LOCAL_PRODUCT_MODULE := true include $(BUILD_PREBUILT)
  • 字体文件通过BUILD_PREBUILT安装到$(TARGET_OUT_PRODUCT)/fonts
  • fonts_customization.xml作为 ETC 模块安装到/product/etc/
  • 所有模块设置LOCAL_PRODUCT_MODULE := true确保安装到 product 分区
3.fonts.mk
PRODUCT_PACKAGES := \ Alibaba-PuHuiTi-Regular.otf \ Alibaba-PuHuiTi-Medium.otf \ fonts_customization.xml
4. device.mk

在产品 Makefile 中引入字体模块:

$(call inherit-product-if-exists, vendor/[product]/fonts/fonts.mk)

遇到的问题及原因

问题:使用 overlay 方式修改 config_bodyFontFamily 不生效

方案描述

最初尝试两步配合:

  1. fonts_customization.xml中定义自定义字体族name="puhuiti"
  2. 通过 RRO(Runtime Resource Overlay)覆盖frameworks/base中的config_bodyFontFamily"puhuiti"
<!-- overlay/frameworks/base/core/res/res/values/config.xml --><stringname="config_bodyFontFamily"translatable="false">puhuiti</string>
现象

adb shell cmd overlay list显示 overlay 已启用([x] android.auto_generated_rro_product__),但字体未生效。

原因

时序问题:系统字体加载发生在 Zygote 启动阶段,此时 RRO 可能还未生效。config_bodyFontFamily的值在字体系统初始化时读取,但 overlay 的应用晚于字体加载,导致系统仍使用默认的sans-serif

解决方案

不依赖 overlay,直接在fonts_customization.xml中将name设为"sans-serif"覆盖系统默认字体族。这样字体替换在FontListParser解析阶段就完成了,不受 RRO 时序影响。

底层原理

customizationType 取值

源码位置:frameworks/base/graphics/java/android/graphics/fonts/FontCustomizationParser.java

目前唯一支持的值"new-named-family"。其他任何值会抛出IllegalArgumentException

覆盖机制

源码位置:frameworks/base/graphics/java/android/graphics/FontListParser.java

FontListParser.readFamilies()解析/system/etc/fonts.xml时的处理逻辑:

  1. 先解析/product/etc/fonts_customization.xml,得到 OEM 自定义的 named families(Map 结构,key 为 name)
  2. 遍历fonts.xml中的 named family 时,检查 OEM Map 中是否存在同名项
  3. 如果存在同名项,跳过系统的 family,不加入结果列表
  4. 最后将 OEM 自定义的 families 全部追加到结果列表中
// FontListParser.java 关键逻辑if(!oemNamedFamilies.containsKey(name)){// OEM 有同名定义时,跳过系统的resultNamedFamilies.add(namedFamilyList);}// ...// 最后追加 OEM 自定义的resultNamedFamilies.addAll(oemNamedFamilies.values());

因此当fonts_customization.xml中定义name="sans-serif"时,系统原有的sans-serif字体族会被完全替换为自定义字体。

验证方法

# 确认字体文件已安装adb shellls-la/product/fonts/Alibaba-PuHuiTi-*.otf# 确认配置文件已安装且内容正确adb shellcat/product/etc/fonts_customization.xml# 检查字体解析是否有错误adb logcat-d|grep-iE"FontCustomization|FontListParser|SystemFonts"

视觉验证:打开设置或任意中文界面,阿里巴巴普惠体与默认 Noto Sans CJK 在字形上差异明显,肉眼可辨。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 19:00:53

主流Attention Backend技术选型与实战场景剖析

1. Attention Backend技术全景解析 当你用ChatGPT生成一段文字&#xff0c;或者让Stable Diffusion画一幅画时&#xff0c;背后都有一个关键组件在默默工作——Attention Backend。这就像汽车发动机里的涡轮增压器&#xff0c;虽然用户看不见&#xff0c;却直接决定了AI模型的&…

作者头像 李华
网站建设 2026/4/14 4:43:52

掌握MCP与Skill:大模型小白/程序员的收藏必备学习指南

掌握MCP与Skill&#xff1a;大模型小白/程序员的收藏必备学习指南 本文深入解析AI Agent中MCP与Skill的核心区别&#xff1a;MCP作为连接层解决"AI能访问什么"&#xff08;外部数据/工具&#xff09;&#xff0c;Skill作为知识层解决"AI知道怎么做什么"&am…

作者头像 李华
网站建设 2026/4/15 20:08:06

收藏!小白程序员入门大模型的30个核心指标详解

收藏&#xff01;小白程序员入门大模型的30个核心指标详解 本文详细介绍了AI产品的30个核心指标&#xff0c;涵盖了模型质量、用户体验、系统效率、业务价值以及数据闭环等五个层面。包括解决率、幻觉率、空答率等模型质量指标&#xff0c;首轮满意度、转人工率、任务完成率等用…

作者头像 李华
网站建设 2026/4/14 4:42:38

稚晖君机械臂技术解析:从设计到实现的嵌入式全栈开发

1. 稚晖君机械臂项目概述 第一次看到稚晖君的机械臂演示视频时&#xff0c;我完全被这个"钢铁侠工作室"级别的作品震撼到了。这个名为Dummy的机械臂不仅能完成抓取、搬运等基础操作&#xff0c;还能实现精细的绘画和写字&#xff0c;甚至可以通过AR界面进行直观控制。…

作者头像 李华