Я перемещаю проект от Ant до Gradle, но там что-то я просто не могу понять.
ФАКТЫ
После создания APK выпуска (т.е. обфускации) я заметил, что приложение было плохо сбой. Ошибка можно суммировать следующим образом:
java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
Отладка (т.е. не запутанная) APK работает очень хорошо, поэтому я догадался, что это связано с моей конфигурацией ProGuard/DexGuard.
Я попытался сохранить ссылку на класс, добавив следующую инструкцию:
-keep class com.mypackage.MyCustomView
и, как результат, релиз APK работает просто отлично. Затем я провел некоторое исследование, и я попробовал эту более конкретную конфигурацию ProGuard/DexGuard:
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
который также работает, и не зависит от класса.
Вопрос
Интересно:
- Почему мне не приходится иметь дело с использованием Ant?
- Какова конкретная причина появления этой ошибки? (следует ответ на первый вопрос)
ANSWER
Ответ от @Blundell был практически правильным. Оказывается, мне не хватает одной строки из конфигурации build.gradle
:
android {
...
buildTypes {
debug {
...
}
release {
proguardFile getDefaultDexGuardFile('dexguard-release.pro') # <----- this line
proguardFile 'dexguard-project.txt'
}
}
}
Кажется, что строка действительно обязательна, так как она служит в качестве базового набора правил для ProGuard/DexGuard. Фактически, это часть файла dexguard-release.pro
:
-keepclassmembers !abstract class !com.google.ads.** extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclassmembers !abstract class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
}
Я обнаружил, что документация немного расплывчата в этом вопросе, я надеюсь, что его можно будет отредактировать, чтобы устранить любую двусмысленность, которая может возникнуть. В общем, моя вина.