ProGuard Android Studio

Если вы собираетесь разместить свое андроид приложение в каком-нибудь маркете, то самое время задуматься о его защите и оптимизации. Одним из решений будет использовать Proguard.

Что такое Proguard

Proguard – это специальная библиотека, которая помогает вам уменьшить размер вашего приложения, усложняет его реинжиниринг и наконец, оптимизирует его, чтобы вы получили более легкое и быстрое приложение.

Какие операции поддерживает Proguard

  • Сжатие – обнаруживает и удаляет неиспользуемые классы, методы, поля и т.д.
  • Обфускация – изменяет имена файлов, методов на короткие бессмысленные имена
  • Оптимизация – анализирует и оптимизирует байт-код методов.

Недостатки

  • Неправильная конфигурация может привести к сбою.
  • Требуется дополнительное тестирование

Как подключить Proguard к проекту

В build.gradle (Module) добавьте следующие строки

buildTypes { 
    // Релизная версия
    release { 
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    //Отладочная версия
    debug{ 
       minifyEnabled true 
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

Вы можете установить minifyEnabled false в любое время, когда захотите удалить влияние Proguard на ваше приложение.

Исключения

Помните о влиянии Proguard на data class, которые предназначены для анализа объекта json с сервера. Следующий фрагмент кода показывает, как вы можете сохранить их нетронутыми:

Как исключить data class для Retrofit которые находятся в пакете models

// Не преобразовывать класс (SampleName)
@Keep
data class SampleName ( ...)

В коде это делать не очень удобно, потом по всему коду лазить и искать @Keep. Можно прописать исключения также в файле конфигурации на класс или даже пакет, и это будет намного удобнее.

# Не преобразовывать весь пакет (models)
-keep class ru.jandroid.mysql_cities.models.** { *; }

# Не преобразовывать класс (City)
-keep class ru.jandroid.mysql_cities.models.City

Конфигурация

То что вы прочитали выше это тоже конфигурация, но ее я выделил отдельно, как наиболее востребованную настройку.

Конфигурация прописывается в файле proguard-rules.pro (см. вышеприведенное изображение). Настройка Proguard это самая основная часть работы с ним и в то же время самая сложная. Неправильный конфиг может легко сломать компиляцию приложения и само приложение.

Конфигурация состоит из трёх важных группы:

  • keep rules (правила сохранения) — Все возможные точки входа в программу. Правила говорящие Proguard, какие классы или части классов нужно сохранить без изменения или какие из модификаций допустимы для конкретных классов.
  • Optimisation tuning (оптимизация) — указывают какие оптимизации допустимы, сколько циклов оптимизации нужно сделать.
  • работа с предупреждениями, ошибками и debugging

Keep rules (правила сохранения)

Это набор опций, предназначенных для того, чтобы защитить код от Proguard. В самом общем виде такое правило выглядит так:

-keep [,modifier,...] class_specification

keep — самая общая из таких опций (есть и другие), говорящая Proguard сохранить сам класс и все его составляющие(class members): поля и методы.
class_specification — шаблон, указывающий на класс(ы) или его части (class members). Общий вид шаблона очень большой, его можно посмотреть в офф. документации.

# Сохранить класс com.example.MyActivity
-keep public class com.example.MyActivity

# Сохранить все публичные классы, наследующие android.app.Activity
-keep public class * extends android.app.Activity

Теперь напишем пример посложнее. Найти все публичные классы, наследующие android.view.View и сохранить в них 3 конструктора с определенными параметрами плюс все публичные методы, с модификатором void, любыми аргументами и именем, начинающимся на set. Все остальные части класса могут быть модифицированы.

-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*(...); 
} 
# Сохранить все классы и все их содержимое в пакете com.habr
-keep class com.habr.** { *; }

modifiers — дополнение к keep-правилу:

  • includedescriptorclasses — помимо указанного класса/метода/поля нужно сохранить все классы, встречающиеся в их дескрипторах.
  • includecode — содержимое метода, на который указывает это конкретное правило, тоже трогать нельзя.
  • allowshrinking — классы, на которые указывает это правило, не являются входными точками (seeds) и их можно удалять, но только если они не используются в самой программе. Однако, если после codeshrinking этот код остался (по причине того, что его кто-то использует), оптимизировать/обфусцировать этот код нельзя.
  • allowoptimization — классы, на которые указывает это правило, можно только оптимизировать, но нельзя удалять или обфусцировать.
  • allowobfuscation — классы, на которые указывает это правило, можно только обфусцировать, но нельзя удалять или оптимизировать.

keep подобные опции

  • keepclassmembers — указывает, что нужно сохранить class members, если сам класс сохранился после code shrinking.
  • keepclasseswithmembers — указывает, что нужно сохранит классы, содержимое которых попадает под указанный шаблон. Например, -keepclasseswithmembers class * { public <init>(android.content.Context); } — сохранит все классы, у которых есть публичный конструктор с одним аргументом типа Context.
  • keepnames — сокращение для -keep,allowshrinking.
  • keepclassmembernames — сокращение для -keepclassmembers,allowshrinking.
  • keepclasseswithmembernames — сокращение для -keepclasseswithmembers,allowshrinking.

Optimisation tuning (оптимизация)

Самой главной опцией здесь является флаг -dontoptimize. Если он присутствует, ни одна оптимизация не будет выполнена и все остальные опции оптимизации будут проигнорированы. Опций оптимизаций много, но самые полезные следующие:

  • -optimizations optimization_filter — перечисление всех способов, которые вы хотите использовать. Лучше использовать тот набор, который указан в proguard-android-optimize.txt или его подмножество. Список всех оптимизаций можно найти тут.
  • -optimizationpasses n — количество циклов оптимизации. Несколько циклов могут улучшить результат. При этом Proguard достаточно умный, чтобы прекратить циклы, если увидит, что результат не улучшился с прошлого раза.
  • -assumenosideeffects class_specification — указывает, что данный метод не имеет сайд-эффектов и только возвращает какое-то значение. Proguard удалит вызовы этого метода, если обнаружит, что возвращаемый им результат не используется. Пожалуй, самое распространенное применение этой опции — удаление всех отладочных логов: -assumenosideeffects class android.util.Log { public static int d(...); }
  • -allowaccessmodification — показать все, что скрыто. Отличная опция, позволяющая избавиться от кучи искусственных accessor методов для вложенных классов. Работает только в паре с -repackageclasses
  • -repackageclasses — разрешает переместить все классы в один указанный пакет. Это больше относится к обфускации, но в то же время, дает хорошие результаты в оптимизации.

Прочие полезные опции

-dontwarn и -dontnote

Proguard очень умный и всегда сообщает о подозрительных местах во время анализа кода, иногда это заметки, иногда — предупреждения. Если ваш build не собирается при включенном Proguard, обязательно прочитайте все производимые им logs, он обязательно напишет, что пошло не так и, скорее всего, даже подскажет как это исправить. Прочитав все сообщения, вы или исправляете проблему, или игнорируете сообщение одной из этих опций, если уверены, что проблемы нет.

Например, бывает, что какая-то java-бибилиотека использует platform-классы, которых нет в android.jar и Proguard предупредит об этом. Если вы уверены, что эта библиотека работает нормально, вы можете отключить это предупреждение -dontwarn java.lang.management.**

-whyareyoukeeping class_specification — полезная опция, которая напечатает причину, по которой Proguard решил не трогать этот класс/метод.

-verbose — печатать более подробные logs и исключения.

-printconfiguration — напечатать полный список опций из всех конфиг-файлов, которые были использованы, включая правила из библиотек и сгенерированные через aapt.

-keepattributes SourceFile, LineNumberTable — сохраняет мета-информацию (имена файлов, нумерацию строк), что бы иметь возможность отлаживать код в IDE и получать осмысленный stacktrace. Обязательно добавляйте эту опцию.

Как выбрать вариант сборки для компиляции

Как найти ошибку у обработанного Proguard приложения

Представьте вы применили Proguard к своему проекту, загрузили его в Google Market и рано или поздно, на каком-нибудь устройстве пользователя вылетела какая-нибудь ошибка, это ведь обязательно произойдет. Тогда как нам разработчикам понять, что это за ошибка, если Proguard запутал файл. Нужно открыть файл mapping.txt и в нем найти, какой измененной переменной соответствует наша оригинальная переменная и таким образом разбираться с ошибками.

Заключение

Использование Proguard — это правильный способ защитить ваше приложение от обратной разработки. Также Proguard экономит время, удаляя неиспользуемые классы и поля, делая приложение более быстрым и менее ёмким. Но Proguard потребует дополнительного процесса тестирования. И нужно быть внимательнее с такими классами как JSON где название классов и переменных должны быть неизменными для правильной работы.

Поделись с друзьями:
Если вам понравилась статья, подписывайтесь на наши социальные сети.

Оставьте комментарий

двадцать − 6 =