确定哪个 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.easysettingscom.android.settings有关,但反编译相应的apk(在/system/app/easysettings和[=14下) =],分别)两者都没有源代码,只有资源(有人也可以解释为什么会这样吗?)。

那么有谁知道如何判断当前的Flipfont包吗?

经过更多的挖掘,我终于找到了一个可行的解决方案。

对于那些使用 Flipfont 的系统,Typeface class 有额外的方法可以让人们获得有关 Flipfont 设置的信息(我想通了 here)。然而,由于这些方法没有在标准 Typeface class 中定义,因此需要使用反射来调用这些方法,当然要捕获异常。

我想出了下面的FontUtilclass,其中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,因此也有必要将前者检查为“后备”(相反按文件名排序)。