300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > android自带中文字体 Android更换系统默认显示的字体使用自定义字体

android自带中文字体 Android更换系统默认显示的字体使用自定义字体

时间:2023-10-10 02:04:03

相关推荐

android自带中文字体 Android更换系统默认显示的字体使用自定义字体

序言

上一篇Android 自定义字体,更换系统默认显示的字体使用自定义字体有讲到怎样指定控件显示指定字体,怎样整个软件显示指定字体,怎样WebView加载指定字体,但是还留下一个怎样修改整个系统的默认字体,由于内容较多,所以单独抽离出来讲,由于要操作系统文件,因此需要Root权限或系统签名,自己在操作前建议先备份下字体配置文件/system/etc/system_fonts.xml和/system/etc/fallback_fonts.xml,否则操作失败有可能开机后无法进入桌面,此时就需要将备份的system_fonts.xml推送到对应目录下并修改为对应的权限。

1、字体加载原理

① Android 系统的字体文件:位于 /system/fonts/ 文件夹下,我们可以到对应的目录下进行查看,可以看出,Android的字体文件都是ttf文件,命令顺序:adb shell ——>cd /system/fonts/ ——>ll,查看结果如下图所示:

image.png

② 在/system/etc/目录下有两个字体配置文件,分别是system_fonts.xml 和 fallback_fonts.xml ,当系统需要加载字体时,会优先从 system_fonts.xml 文件开始查找,如果没有找到再进入 fallback_fonts.xml 查找。

system_fonts.xml示范文件

sans-serif

arial

helvetica

tahoma

verdana

Roboto-Regular.ttf

Roboto-Bold.ttf

Roboto-Italic.ttf

Roboto-BoldItalic.ttf

sans-serif-light

Roboto-Light.ttf

Roboto-LightItalic.ttf

sans-serif-thin

Roboto-Thin.ttf

Roboto-ThinItalic.ttf

sans-serif-condensed

RobotoCondensed-Regular.ttf

RobotoCondensed-Bold.ttf

RobotoCondensed-Italic.ttf

RobotoCondensed-BoldItalic.ttf

serif

times

times new roman

palatino

georgia

baskerville

goudy

fantasy

cursive

ITC Stone Serif

DroidSerif-Regular.ttf

DroidSerif-Bold.ttf

DroidSerif-Italic.ttf

DroidSerif-BoldItalic.ttf

Droid Sans

DroidSans.ttf

DroidSans-Bold.ttf

monospace

courier

courier new

monaco

DroidSansMono.ttf

fallback_fonts.xml 示范文件

DroidNaskh-Regular.ttf

DroidNaskhUI-Regular.ttf

DroidSansEthiopic-Regular.ttf

DroidSansHebrew-Regular.ttf

DroidSansHebrew-Bold.ttf

NotoSansThai-Regular.ttf

NotoSansThai-Bold.ttf

NotoSansThaiUI-Regular.ttf

NotoSansThaiUI-Bold.ttf

DroidSansArmenian.ttf

DroidSansGeorgian.ttf

NotoSansDevanagari-Regular.ttf

NotoSansDevanagari-Bold.ttf

NotoSansDevanagariUI-Regular.ttf

NotoSansDevanagariUI-Bold.ttf

NotoSansTamil-Regular.ttf

NotoSansTamil-Bold.ttf

NotoSansTamilUI-Regular.ttf

NotoSansTamilUI-Bold.ttf

NotoSansMalayalam-Regular.ttf

NotoSansMalayalam-Bold.ttf

NotoSansMalayalamUI-Regular.ttf

NotoSansMalayalamUI-Bold.ttf

NotoSansBengali-Regular.ttf

NotoSansBengali-Bold.ttf

NotoSansBengaliUI-Regular.ttf

NotoSansBengaliUI-Bold.ttf

NotoSansTelugu-Regular.ttf

NotoSansTelugu-Bold.ttf

NotoSansTeluguUI-Regular.ttf

NotoSansTeluguUI-Bold.ttf

NotoSansKannada-Regular.ttf

NotoSansKannada-Bold.ttf

NotoSansKannadaUI-Regular.ttf

NotoSansKannadaUI-Bold.ttf

NotoSansKhmer-Regular.ttf

NotoSansKhmer-Bold.ttf

NotoSansKhmerUI-Regular.ttf

NotoSansKhmerUI-Bold.ttf

NotoSansLao-Regular.ttf

NotoSansLao-Bold.ttf

NotoSansLaoUI-Regular.ttf

NotoSansLaoUI-Bold.ttf

NanumGothic.ttf

Padauk-book.ttf

Padauk-bookbold.ttf

NotoSansSymbols-Regular.ttf

AndroidEmoji.ttf

NotoColorEmoji.ttf

DroidSansFallback.ttf

MTLmr3m.ttf

2、为系统添加一个默认字体

修改系统默认字体的原理:根据系统字体加载原理可知,我们只需要在路径 /system/fonts/ 下添加我们自定义的ttf字体文件,然后修改 /system/etc/system_fonts.xml 字体配置文件,按照响应的格式添加一个节点,由于需要系统默认使用该字体,因此该节点需要是根节点familyset下的第一个子节点,系统在system_fonts.xml中找到了该字体的配置,故不会去fallback_fonts.xml 寻找,因此也只需要修改这一个配置文件即可,文件修改成功后需要注意已修改文件的读写权限(否则会没有效果),为了方便,我们设置全部用户可读可写。

① 判断系统字体库是否已有需要添加的字体文件

/**

* 检查字体文件是否存在系统目录中

* @param fontName 字体文件名称

* @return ture:已存在

*/

private boolean checkFontTTFFile(String fontName) {

File dir = new File(systemFontsDir);

File[] files = dir.listFiles(); //字库列表

if (files != null && files.length > 0) {

for (int i = 0; i < files.length; i++) {

File file = files[i];

if (file.exists() && file.getName().equals(fontName)) {

return true;

}

}

}

return false;

}

② 若①判断后没有则需要拷贝字体文件到对应路径下

/**

* 拷贝字体文件

*

* @param fontName 字体文件名

* @param destDir 目标目录

*/

private void copyFontTTF(String fontName, String destDir) {

try {

//将Assets文件夹中的字体文件读出来

InputStream inputStream = getAssets().open("fonts/" + fontName);

//将字体文件写入到sd卡中 ,不能直接写入 /system/fonts/下,因为没有写文件的权限

File file = new File(getCacheDir(), fontName);

FileOutputStream fos = new FileOutputStream(file);

int leng = 0;

byte[] buffer = new byte[1024];

while (-1 != (leng = inputStream.read(buffer))) {

fos.write(buffer, 0, leng);

}

fos.flush();

fos.close();

inputStream.close();

runRootCommand("cp " + file.getAbsolutePath() + " " + destDir); //使用命令进行文件拷贝

Log.e(TAG, "copyFontTTF: 字体文件拷贝成功");

} catch (Exception e) {

e.printStackTrace();

}

}

③ 判断字体配置文件 system_fonts.xml 是否已有该节点,若有则不进行操作,若无进行步骤④

/**

* 检查指定的XML文件中是否有节点名称为 refNodeName 的值为 compareNodeValue 的节点

*

* @param refNodeName 参考的节点名称

* @param compareNodeValue 被比较的节点名称下的值

* @param file XML文件

* @return ture存在该节点

*/

private boolean checkXmlNode(String refNodeName, String compareNodeValue, File file) {

boolean result = false;

try {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(file); // 解析XML到内存中

NodeList nodeList = doc.getElementsByTagName(refNodeName);

for (int i = 0; i < nodeList.getLength(); i++) { //判断有没有该节点

Node item = nodeList.item(i);

String itemValue = item.getFirstChild().getNodeValue();

if (itemValue.equals(compareNodeValue)) {

result = true;

}

}

} catch (Exception e) {

e.printStackTrace();

}

Log.e(TAG, "checkXmlNode: 检查是否存在该节点refNodeName=" + refNodeName + ",compareNodeValue=" + compareNodeValue + ",result=" + result);

return result;

}

④ 若③中没有该节点,则在根节点familyset下的第一位置添加该节点并保存

/**

* 向system_fonts.xml文件增加一个节点

*

* @param nodeValue 节点的值

*/

private void addSystemFontNote(String nodeValue) {

try {

File file = new File(system_fonts);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(file); // 解析XML到内存中

Node nodeFamilyset = doc.getElementsByTagName("familyset").item(0);

Element elementFamily = doc.createElement("family");

Element elementNameset = doc.createElement("nameset");

Element elementName = doc.createElement("name");

elementName.setTextContent(nodeValue);

elementNameset.appendChild(elementName);//将name节点设置为nameset的子节点

Element elementFileset = doc.createElement("fileset");

Element elementFile = doc.createElement("file");

elementFile.setTextContent(nodeValue + ".ttf");

elementFileset.appendChild(elementFile);

elementFamily.appendChild(elementNameset);

elementFamily.appendChild(elementFileset);

Node nodeFamily = doc.getElementsByTagName("family").item(0);

nodeFamilyset.insertBefore(elementFamily, nodeFamily); //将节点elementFamily插入到节点nodeFamily之前

//保存到文件中

saveXmlFile(doc, system_fonts);

Log.e(TAG, "addSystemFontNote: 节点添加成功");

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 保存xml文件到指定路径

* @param doc 要保存的XML文档对象

* @param destFile 目标路径

* @throws TransformerException

*/

private void saveXmlFile(Document doc, String destFile) throws TransformerException {

Transformer transformer = TransformerFactory.newInstance().newTransformer();//创建一个用来转换DOM对象的工厂对象并获得转换器对象

DOMSource domSource = new DOMSource(doc); //定义要转换的源对象

File temFile = new File(getCacheDir(), "tem.xml");

StreamResult streamResult = new StreamResult(temFile); //定义要转换到的目标文件

transformer.transform(domSource, streamResult); //开始转换 ,

// runRootCommand("rm " + system_fonts);

runRootCommand("cat " + temFile.getAbsolutePath() + " > " + destFile);//复制文件内容

Log.e(TAG, "saveXmlFile: 保存文件成功," + destFile);

}

⑤ 完整的调用流程

private String system_fonts = "/system/etc/system_fonts.xml";

private String fallback_fonts = "/system/etc/fallback_fonts.xml";

private String systemFontsDir = "/system/fonts/";//系统存放字体文件的路径

public void ywsflsjtForSystem(View view) {

String fontName = "ywsflsjt.ttf";

runRootCommand("mount -o remount rw /system"); //重新挂载该路径为可读写模式

//以下操作建议在线程中执行

if (!checkFontTTFFile(fontName)) {

copyFontTTF(fontName, systemFontsDir);

}

runRootCommand("chmod 777 " + new File(systemFontsDir, fontName).getAbsolutePath());//修改字体文件的权限

String compareNodeValue = fontName.split("\\.")[0];

boolean node = checkXmlNode("name", compareNodeValue, new File(system_fonts));

if (node == false) { //没有该节点,在头部插入该节点

addSystemFontNote(compareNodeValue);

runRootCommand("chmod 777 " + system_fonts);

}

runRootCommand("reboot"); //要使修改后的字体生效需要重启系统

}

⑥ 运行Root指令的方法

/**

* 请求ROOT权限后执行命令(最好开启一个线程)

*

* @param cmd (pm install -r *.apk)

* @return

*/

public boolean runRootCommand(String cmd) {

Process process = null;

DataOutputStream os = null;

BufferedReader br = null;

StringBuilder sb = null;

try {

process = Runtime.getRuntime().exec("su");

os = new DataOutputStream(process.getOutputStream());

os.writeBytes(cmd + "\n");

os.writeBytes("exit\n");

br = new BufferedReader(new InputStreamReader(

process.getInputStream()));

sb = new StringBuilder();

String temp = null;

while ((temp = br.readLine()) != null) {

sb.append(temp + "\n");

if ("Success".equalsIgnoreCase(temp)) {

return true;

}

}

process.waitFor();

} catch (Exception e) {

Log.e(TAG, "异常:" + e.getMessage());

} finally {

try {

if (os != null) {

os.flush();

os.close();

}

if (br != null) {

br.close();

}

process.destroy();

} catch (Exception e) {

return false;

}

}

return false;

}

3、删除已添加的系统默认字体

和添加字体相对应,需要先删除字体文件,然后再删除 system_fonts.xml和fallback_fonts.xml两文件中的对应节点,由于我们没有修改过fallback_fonts.xml文件因此不需要做删除操作

① 删除节点是需要调用checkXmlNode方法坚持节点是否存在,若存在则删除数据

/**

* 删除 system_fonts.xml文件中的节点名称name值为 nodeValue的节点

*

* @param nodeValue

*/

private void deleteSystemFontNote(String nodeValue) {

Log.e(TAG, "deleteSystemFontNote: 删除文件" + system_fonts + "中的节点:" + nodeValue);

try {

File file = new File(system_fonts);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(file); // 解析XML到内存中

NodeList nodeListName = doc.getElementsByTagName("name");

for (int i = 0; i < nodeListName.getLength(); i++) {

Node item = nodeListName.item(i);

String value = item.getFirstChild().getNodeValue();

if (value != null && nodeValue.equals(value)) {

Node nodenameset = item.getParentNode();

Node nodefamily = nodenameset.getParentNode();

Node nodefamilyset = nodefamily.getParentNode();

nodefamilyset.removeChild(nodefamily);

saveXmlFile(doc, system_fonts);

Log.e(TAG, "删除节点成功,nodeValue=" + nodeValue);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

② 完整的删除流程

public void deleteYwsflsjtForSystem(View view) {

String fontName = "ywsflsjt.ttf";

String nodeName = fontName.split("\\.")[0];

runRootCommand("mount -o remount rw /system"); //重新挂载该路径为可读写模式

runRootCommand("rm " + systemFontsDir + fontName); //删除字体文件

if (checkXmlNode("name", nodeName, new File(system_fonts))) {

deleteSystemFontNote(nodeName);

runRootCommand("chmod 777 " + system_fonts);

}

runRootCommand("reboot"); //要使修改后的字体生效需要重启系统

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。