Переход на Gradle: почему я должен запрещать запутывание пользовательских представлений?

Я перемещаю проект от 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);
}

Я обнаружил, что документация немного расплывчата в этом вопросе, я надеюсь, что его можно будет отредактировать, чтобы устранить любую двусмысленность, которая может возникнуть. В общем, моя вина.

Ответ 1

Скорее всего, Ant использовал другой файл конфигурации,

Также с помощью Gradle вам нужно явно указать, что вы хотите использовать файл конфигурации proguard Android, например, использовать несколько файлов правил, например:

    proguardFile getDefaultProguardFile('proguard-android.txt')
    proguardFile 'your/sepcific/folder/proguard.cfg'

(Я помню, что Ant никогда не использовал файл SDK proguard, и он рекомендовал скопировать всю конфигурацию).