确定哪个 Flipfont 包处于活动状态(并在 WebViews 上使用它)
Determine which Flipfont package is active (and use it on WebViews)
首先我应该解释一下我的最终目标是什么。我开发了 Android 应用程序,主要使用 WebView。他们在各个方面都很棒,但他们做得不好的一件事是 "matching the native UI",尤其是字体。有些手机(比如三星手机)支持使用 Flipfont 切换整个系统的默认字体,但由于某些原因,没有浏览器(据我所知)适应该设置并使用 Flipfont 设置显示网页。 WebViews也是如此,从而造成不一致的用户体验。
不过我觉得应该有办法让WebViews使用Flipfont字体。通过研究iFont的反编译源代码,我想我已经弄清楚了如何从给定的Flipfont包的资源中提取.ttf文件,包名总是以com.monotype.android.font
开头。在那之后,我应该可以让 WebView 使用那个 .ttf 文件作为默认字体。问题是,我不知道应该提取哪个包,也就是说,我不知道当前正在使用哪个 Flipfont 包(如果有的话)。 iFont 似乎也无法确定;该应用程序中没有地方明确告诉我 "You're using font xxx".
但显然必须有一种方法可以确定这一点,因为 Flipfont 设置对话框向我显示了这一点。但是,我未能反编译设置对话框来研究它是如何完成的。从Logcat来看,设置对话框似乎与包com.sec.android.easysettings
和com.android.settings
有关,但反编译相应的apk(在/system/app/easysettings
和[=14下) =],分别)两者都没有源代码,只有资源(有人也可以解释为什么会这样吗?)。
那么有谁知道如何判断当前的Flipfont包吗?
经过更多的挖掘,我终于找到了一个可行的解决方案。
对于那些使用 Flipfont 的系统,Typeface
class 有额外的方法可以让人们获得有关 Flipfont 设置的信息(我想通了 here)。然而,由于这些方法没有在标准 Typeface
class 中定义,因此需要使用反射来调用这些方法,当然要捕获异常。
我想出了下面的FontUtil
class,其中getFlipFont
方法returns当前Flipfont.ttf文件的File
对象如果有一个,或者 null
如果有 none.
import android.content.Context;
import android.graphics.Typeface;
import java.io.File;
import java.lang.reflect.Method;
public class FontUtil {
@SuppressWarnings("JavaReflectionMemberAccess")
public static File getFlipFont(Context context) {
try {
Method m = Typeface.class.getMethod("getFontPathFlipFont", Context.class, int.class);
String path = m.invoke(null, context, 1).toString();
if (!path.equals("default")) {
File file = new File(path + "/DroidSansFallback.ttf");
if (file.exists()) return file;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
在那之后,如果有人关心的话,我的目标是通过以下方式实现的。在我的应用程序的网页上添加以下 CSS:
@font-face {
font-family: Flipfont;
src: url(flipfont.ttf);
}
body {
font-family: Flipfont;
}
接下来,在我的活动中使用类似这样的东西:
private File flipFont;
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
flipFont = FontUtil.getFlipFont(this);
...
webView.setWebViewClient(new AppWebViewClients());
...
}
private class AppWebViewClients extends WebViewClient {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (url.endsWith("flipfont.ttf") && flipFont != null) {
try {
InputStream stream = new FileInputStream(flipFont);
return new WebResourceResponse("application/x-font-ttf", "UTF-8", stream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
return super.shouldInterceptRequest(view, request);
}
}
现在我的 WebView 应用程序使用与任何其他本机应用程序完全相同的字体。
2021.4.25 更新:
今天发现在Samsung Note 9上,方法名是semGetFontPathOfCurrentFontStyle()
,所以也应该看看这个方法是否可用。此外,在某些更改字体的方法中,字体文件名可能最终成为 DroidSans.ttf
而不是 DroidSansFallback.ttf
,因此也有必要将前者检查为“后备”(相反按文件名排序)。
首先我应该解释一下我的最终目标是什么。我开发了 Android 应用程序,主要使用 WebView。他们在各个方面都很棒,但他们做得不好的一件事是 "matching the native UI",尤其是字体。有些手机(比如三星手机)支持使用 Flipfont 切换整个系统的默认字体,但由于某些原因,没有浏览器(据我所知)适应该设置并使用 Flipfont 设置显示网页。 WebViews也是如此,从而造成不一致的用户体验。
不过我觉得应该有办法让WebViews使用Flipfont字体。通过研究iFont的反编译源代码,我想我已经弄清楚了如何从给定的Flipfont包的资源中提取.ttf文件,包名总是以com.monotype.android.font
开头。在那之后,我应该可以让 WebView 使用那个 .ttf 文件作为默认字体。问题是,我不知道应该提取哪个包,也就是说,我不知道当前正在使用哪个 Flipfont 包(如果有的话)。 iFont 似乎也无法确定;该应用程序中没有地方明确告诉我 "You're using font xxx".
但显然必须有一种方法可以确定这一点,因为 Flipfont 设置对话框向我显示了这一点。但是,我未能反编译设置对话框来研究它是如何完成的。从Logcat来看,设置对话框似乎与包com.sec.android.easysettings
和com.android.settings
有关,但反编译相应的apk(在/system/app/easysettings
和[=14下) =],分别)两者都没有源代码,只有资源(有人也可以解释为什么会这样吗?)。
那么有谁知道如何判断当前的Flipfont包吗?
经过更多的挖掘,我终于找到了一个可行的解决方案。
对于那些使用 Flipfont 的系统,Typeface
class 有额外的方法可以让人们获得有关 Flipfont 设置的信息(我想通了 here)。然而,由于这些方法没有在标准 Typeface
class 中定义,因此需要使用反射来调用这些方法,当然要捕获异常。
我想出了下面的FontUtil
class,其中getFlipFont
方法returns当前Flipfont.ttf文件的File
对象如果有一个,或者 null
如果有 none.
import android.content.Context;
import android.graphics.Typeface;
import java.io.File;
import java.lang.reflect.Method;
public class FontUtil {
@SuppressWarnings("JavaReflectionMemberAccess")
public static File getFlipFont(Context context) {
try {
Method m = Typeface.class.getMethod("getFontPathFlipFont", Context.class, int.class);
String path = m.invoke(null, context, 1).toString();
if (!path.equals("default")) {
File file = new File(path + "/DroidSansFallback.ttf");
if (file.exists()) return file;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
在那之后,如果有人关心的话,我的目标是通过以下方式实现的。在我的应用程序的网页上添加以下 CSS:
@font-face {
font-family: Flipfont;
src: url(flipfont.ttf);
}
body {
font-family: Flipfont;
}
接下来,在我的活动中使用类似这样的东西:
private File flipFont;
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
flipFont = FontUtil.getFlipFont(this);
...
webView.setWebViewClient(new AppWebViewClients());
...
}
private class AppWebViewClients extends WebViewClient {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (url.endsWith("flipfont.ttf") && flipFont != null) {
try {
InputStream stream = new FileInputStream(flipFont);
return new WebResourceResponse("application/x-font-ttf", "UTF-8", stream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
return super.shouldInterceptRequest(view, request);
}
}
现在我的 WebView 应用程序使用与任何其他本机应用程序完全相同的字体。
2021.4.25 更新:
今天发现在Samsung Note 9上,方法名是semGetFontPathOfCurrentFontStyle()
,所以也应该看看这个方法是否可用。此外,在某些更改字体的方法中,字体文件名可能最终成为 DroidSans.ttf
而不是 DroidSansFallback.ttf
,因此也有必要将前者检查为“后备”(相反按文件名排序)。