我正在为公司的项目编写单元测试(使用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都无济于事。资产目录正确放在'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"/>
自定义字体文字视图:
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);
}
}
}
attrs.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应该受到责备吗?
答案 0 :(得分:3)
它的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.