android 系统字体更改

565 阅读2分钟

代码实现:

1.添加字体资源文件到fonts中

frameworks/base/data/fonts/

例如:Ndot-55.otf

2.修改fonts.xml文件

frameworks/base/data/fonts/fonts.xml

例如:

Ndot-55.ttf

3.修改编译文件,把字体资源文件编译进系统

frameworks/base/data/fonts/Android.mk

追加字体资源文件

例如:

PRODUCT_PACKAGES := \

Ndot-55.otf

如果是dp文件

frameworks/base/data/fonts/Android.dp

prebuilt_font {

name: "Ndot-55.otf",

src: "Ndot-55.otf",

}

4.新增根据prop值动态修改Typeface.java

frameworks/base/graphics/java/android/graphics/Typeface.java

在create方法中去读取prop,如果有值则替换返回的familyName

5.编译刷机


然后通过adb命令更改

机器需要先 adb root && adb remoun

1.adb push Ndot-55.ttf /system/fonts

2.修改fonts.xml文件

在文件中添加

Ndot-55.ttf

adb pull /system/etc/fonts.xml

adb push fonts.xml /system/etc/

3.修改prop值,如果无效试着重启机器

adb shell setprop persist.sys.cus_font ndot-55

adb reboot

参考

blog.csdn.net/Sqq_yj/arti…

不重启使得字体生效

/frameworks/base/core/java/android/graphics/fonts/FontManager.java

需要权限 
<uses-permission android:name="android.permission.UPDATE_FONTS"/> 

1)getFontConfig() 
mIFontManager.getFontConfig(); 
2)updateFontFamily() 
mIFontManager.updateFontFamily()

/frameworks/base/core/java/com/android/internal/graphics/fonts/IFontManager.aidl

interface IFontManager { 

@EnforcePermission("UPDATE_FONTS") 
FontConfig getFontConfig(); 
int updateFontFamily(in List<FontUpdateRequest> request, int baseVersion); 
    
}

/frameworks/base/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java /frameworks/base/services/core/java/com/android/server/graphics/fonts/FontManagerService.java

FontManagerService extends IFontManager.Stub 
private static final String FONT_FILES_DIR = "/data/fonts/files";
private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml"; 
方法initialize() mUpdatableFontDir.loadFontFileMap(); 
addFileToMapIfSameOrNewer(); putFontFileInfo(fontFileInfo); mFontFileInfoMap.put(info.getPostScriptName(), info);

方法updateFontFamily() 

1)update(List<FontUpdateRequest> requests)
mUpdatableFontDir.update(requests); 
--> 
backupMap = new ArrayMap<>(mFontFileInfoMap);
curConfig = readPersistentConfig(); //该方法是读取config中的参数 
familyMap = new HashMap<>(); 遍历curConfig和requests,put到familyMap中 newConfig.fontFamilies.addAll(familyMap.values()); 
writePersistentConfig(newConfig);//将newConfig写入config.xml中 
mConfigVersion++;

2)updateSerializedFontMap(); 

SharedMemory serializedFontMap = serializeFontMap(getSystemFontConfig()); 
-- > 
SystemFonts.buildSystemFallback();
SystemFonts.buildSystemTypefaces(); 
return Typeface.serializeFontMap(typefaceMap); 
-- > 
setSerializedFontMap(serializedFontMap); 
mSerializedFontMap = serializedFontMap; 
getCurrentFontMap()返回的就是mSerializedFontMap
public static final class Lifecycle extends SystemService { 
private final FontManagerService mService; 
public Lifecycle(@NonNull Context context, boolean safeMode) { 
super(context); 
mService = new FontManagerService(context, safeMode); 
} 

@Override public void onStart() { 
LocalServices.addService(FontManagerInternal.class, 
new FontManagerInternal() { 
@Override
@Nullable 
public SharedMemory getSerializedSystemFontMap() { 
if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) { 
return null;
} 
return mService.getCurrentFontMap();
} 
});
publishBinderService(Context.FONT_SERVICE, mService); 
}
}

系统是如何发生改变的

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

SharedMemory serializedSystemFontMap = null; 
final FontManagerInternal fm = LocalServices.getService(FontManagerInternal.class); 
if (fm != null) {
serializedSystemFontMap = fm.getSerializedSystemFontMap();
} 
thread.bindApplication(serializedSystemFontMap)

source.android.google.cn/docs/core/a…

对接接口:

import android.graphics.fonts.FontFamilyUpdateRequest; 
import android.graphics.fonts.FontFileUpdateRequest; 
import android.graphics.fonts.FontManager; 
import android.graphics.fonts.FontStyle; 
import android.os.ParcelFileDescriptor; 
import android.text.FontConfig; 
import java.nio.file.Files; 
import java.io.File;
import java.nio.file.Paths;
import java.util.Arrays; 
import java.io.IOException; 
import java.util.List;
import static android.graphics.fonts.FontStyle.FONT_SLANT_UPRIGHT; 
import static android.graphics.fonts.FontStyle.FONT_WEIGHT_BOLD; 
import static android.graphics.fonts.FontStyle.FONT_WEIGHT_NORMAL; 
import static android.graphics.fonts.FontStyle.FONT_WEIGHT_MEDIUM; 
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import 
com.android.compatibility.common.util.SystemUtil; 

familyName = xml 标签中的 <family name="ndot-55"> 

private static final String OPPO_SANS_REGULAR_POSTSCRIPT_NAME = "OPPOSans-Regular";
private static final String OPPO_SANS_REGULAR_TTF = "/data/local/tmp/OPPOSans-Regular.ttf";

为字体文件签名 
由于字体文件是存在风险的资源,因此必须通过可信的密钥对其进行验证。请仔细检查所有要更新的字体文件,然后使用您的私钥对其签名。此签名必须符合 fs-verity 的要求 
private static final String OPPO_SANS_REGULAR_SIG = "/data/local/tmp/OPPOSans-Regular.sig"; 

private int onChangeFont(String familyName) throws IOException { List<FontFamilyUpdateRequest.Font> fonts = 
Arrays.asList( new FontFamilyUpdateRequest.Font.Builder(OPPO_SANS_REGULAR_POSTSCRIPT_NAME,
new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT)).build() 
); 
FontFamilyUpdateRequest.FontFamily fontFamily = new FontFamilyUpdateRequest.FontFamily.Builder(familyName, fonts).build();
byte[] regularSig = Files.readAllBytes(Paths.get(OPPO_SANS_REGULAR_SIG)); 
try (ParcelFileDescriptor regularFd = ParcelFileDescriptor.open(
new File(OPPO_SANS_REGULAR_TTF), MODE_READ_ONLY); )
{ 
return SystemUtil.runWithShellPermissionIdentity(() -> { 
FontConfig fontConfig = mFontManager.getFontConfig(); 
return mFontManager.updateFontFamily(new FontFamilyUpdateRequest.Builder() .addFontFileUpdateRequest( 
new FontFileUpdateRequest(regularFd, regularSig)) 
.addFontFamily(fontFamily) 
.build(), fontConfig.getConfigVersion());
});
}
}