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"); //要使修改后的字體生效需要重啟系統
}
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的android自带中文字体,Android更换系统默认显示的字体使用自定义字体的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言读取acc文件的采样率,C语言文件
- 下一篇: android调用网页方法,Androi