android - android gradle 插件升级后单元测试期间无法加载自定义字体

标签 android android-gradle-plugin robolectric

我正在为公司的项目编写单元测试(使用 robolectric 3.1)。在最近的提交中,android gradle plugin 版本从 2.1.0 更新到 2.2.3。 每当测试调用加载自定义字体的代码时,此更改都会导致测试失败。

将插件版本更改回 2.1.0 可以解决问题,但我被告知需要更改版本并且必须保留。反正我们的CI构建环境测试没有问题,看来只有我本地构建有问题。

我更新了 JRE 和 SDK,都是 1.8(并将 JAVA_HOME 设置为更新的 JDK 目录)和 Android Studio,但无济于事。 Assets 目录正确放置在“main”下,而不是“res”目录下(字体在 app/src/main/assets/fonts/中)。 清理项目并在缓存失效的情况下重新启动 IDE 也无济于事。

关闭 Instant Run 后问题仍然存在,因此它不是此处描述的问题 https://code.google.com/p/android/issues/detail?id=213454

build.gradle:

dependencies {
        (...)
        classpath 'com.android.tools.build:gradle:2.2.3'
}
android {
    compileSdkVersion 23
    buildToolsVersion '23.0.2'

    defaultConfig {
        applicationId "com.example.app"
        minSdkVersion 16
        targetSdkVersion 22
        multiDexEnabled true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    (...)
}

使用自定义字体(布局)的示例代码:

<com.example.CustomFontTextView
                (...)
                android:textAppearance="?android:attr/textAppearanceSmall"
                custom:customFont="@string/custom_font_path"/>

自定义字体 TextView :

public class CustomFontTextView extends TextView {
    public CustomFontTextView(final Context context){
        super(context);
    }

    public CustomFontTextView (final Context context, final AttributeSet attrs){
        super(context, attrs);

        if(!isInEditMode()){
            initTextView(context, attrs);
        }
    }

    public CustomFontTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if(!isInEditMode()){
            initTextView(context, attrs);
        }
    }

    private void initTextView(final Context context, final AttributeSet attrs){

        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomFontView);
        String customFont = attributes.getString(R.styleable.CustomFontView_customFont);
        setText(getText());
        if(customFont!=null){
            Typeface tf = getTypeface(context, customFont);
            setTypeface(tf);
        }
        attributes.recycle();
    }

    private Typeface getTypeface(final Context context, final String customFontPath) {
        return Typeface.createFromAsset(context.getAssets(), customFontPath);
    }

    public void setTypeFace(Context con, String font){
        if(font != null && con != null){
            Typeface tf = getTypeface(con, font);
            setTypeface(tf);
        }
    }
}

属性.xml:

<declare-styleable name="CustomFontView">
    <attr name="customFont" format="string" />
</declare-styleable>

字体路径保存在字符串中:

<string name="custom_font_path">fonts/CustomFont.ttf</string>

异常(在布局​​膨胀期间发生):

android.view.InflateException: XML file build\intermediates\res\merged\mock\debug\layout\layout.xml line #-1 (sorry, not yet implemented): Error inflating class <unknown>
(...)
Caused by: java.lang.RuntimeException: Font not found at [build\intermediates\bundles\mock\debug\assets\fonts\CustomFont.ttf]

是什么导致字体加载失败? Robolectric 是罪魁祸首吗?

最佳答案

这确实是 Robolectric

https://github.com/robolectric/robolectric/issues/2647

Android gradle 插件内部实现在 2.2 中发生了变化,但 Robolectric 3.1 仍然基于旧的实现。它已在 Robolectric 3.2 中修复。除了 robolectric 升级,otbinary 在 github 上建议的解决方案也很有用:

android.applicationVariants.all { variant ->
    def productFlavor = "${variant.productFlavors[0].name.capitalize()}"
    def buildType = "${variant.buildType.name.capitalize()}"
    tasks["compile${productFlavor}${buildType}UnitTestSources"].dependsOn(tasks["merge${productFlavor}${buildType}Assets"])
}
This creates a dependency for all compile*UnitTestSources Gradle tasks on the corresponding merge*Assets tasks. The merge tasks copy all assets to app/build/intermediates/assets, where Robolectric finds them.

关于android - android gradle 插件升级后单元测试期间无法加载自定义字体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42231405/

相关文章:

android - gradle 将 "apply plugin"放在哪里?

Android Studio 覆盖率报告未在带注释的方法上运行

android - 启动时启动 Activity

android - 使用 LeakCanary 在 DeathMonitor 上发生内存泄漏

android - 怎么用exoplayer玩m3u8,黑屏

android - 启用 Jack 时的编译异常

android - "Gradle build finished with 188 error(s) "执行任务 android 依赖

android - 不确定的微调器与 id.menu_refresh 大小不同?

java - Robolectric 测试抛出 RuntimeException : java. lang.ClassNotFoundException

java - Android - 使用 RxAndroid 进行 Robolectric 测试?