Защита кода приложения это то, о чем не всегда задумывается разработчик, но обфускация при сборке - это не только защита, но и эффективный способ ужать размер конечного APK, а иногда и оптимизировать исполнение программы.
С учетом того, на сколько сейчас просто настроить Proguard для разработки под Android, не использовать эту возможность крайне не логично.
Интересный факт: существует контест на написание самого креативного обфусцированного кода на СИ "The International Obfuscated C Code Contest". Можно посмотреть на разные примеры эпичного компилируемого кода.
Что делает Proguard?
Proguard - наверное самый часто используемый инструмент для обфускации кода при разработке под Андроид, он бесплатный, с открытым исходным кодом. Есть еще DexGuard для более продвинутой защиты вашего приложения.
Удаление неиспользуемого кода
Неиспользуемый код - лишние байты информации, Proguard удаляет его, экономя на конечном размере Apk.
Надо быть осторожным, если код используется через рефлексию, в таком случае обфусцированное приложение сломается у пользователя на устройстве.
Оптимизация байт кода
Proguard умеет работать с исходниками на уровне байткода, применяя оптимизации, например такие как
- Замена умножение и деление на степень двойки на сдвиг,
- Замена интерфейсов с единственной реализацией,
- Замена по возможности enum на численные константы,
Надо понимать, что Proguard работает на уровне Java байт кода, в то время как Андроид приложения исполняются на Dalvik Virtual Machine (DVM) используя Dalvik байт код. Оптимизации одного кода могут плохо отразиться на втором, как следствие надо внимательно относится к данному процессу.
Как настроить Proguard для Android?
Максимально подробную инструкцию от первоисточника можно найти в официальной документации Андроида, пройдемся по порядку:
Изменить build.gradle
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
- getDefaultProguardFile('proguard-android.txt') - базовый конфиг для Андроид приложения из Android SDK, по умолчанию в нем отключена оптимизация, т.к. Dex может ее не пережить, попробовать ее включить можно, использовав вместо этого getDefaultProguardFile('proguard-android-optimize.txt')
- proguard-rules.pro - конфигурация непосредственно вашего модуля
Не следует включать обфускацию для Debug сборок, потому как этот процесс занимает время. Зачем тратить его просто на ожидание на этапе разработки?
Добавить конфиги для используемых библиотек
Редко когда приложение не использует сторонние библиотеки. Очень часто сторонние модули требуют дополнительных настроек для Proguard. Но! Существует проект на GitHub - сборник сниппетов для популярных библиотек, в котором уже есть большинство нужных конфигов.
Достаточно положить все файлы настроек в папку proguard вашего модуля (по умолчанию app ) и добавить в build.gradle строку, чтобы блок, отвечающий за proguard выглядел следующим способом:
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt')
proguardFiles(file('./proguard').listFiles())
proguardFiles(file('./proguard').listFiles()) возьмет все файлы конфигов из папки proguard и применит их при обфускации вашего приложения.
Проверить, что ваше приложение работает
Причем проверять не Debug сборку без обфускации, а именно "оптимизированное" приложение. Лично часто натыкался на то, что у меня все работает, а у тестировщика сломано. Далеко не сразу соображаешь, что дело именно в ProGuardе.
Проверить сериализацию данных
Большинство приложений сегодня работает с бэкендом. Запрос и ответ зачастую описан примерно таким классом
public final class BookResponse {
private String author;
private String title;
}
и все корректно работает. Мы получаем данные. Все хорошо.
Приложение уходит тестировщику, у которого опять все сломано. Дело в том, что при обфускации меняются в том числе имена приватных методов, полей и другой "служебной" информации. В следствии чего при автоматическом парсинге JSON например, сериализатор будет искать поле не author , а не пойми какое.
Решений по сути есть 2
- Запретить обфускацию классов, учавствующих в сетевом обмене на уровне конфигурации модуля,
- Добавить имя для сериализации.
Я выбираю второе по нескольким причинам
- Имя параметра не зависит от имени параметра на сервере,
- Руководствуясь AOSP Java Code Style for Contributors все непубличные члены класса у меня имеют префикс m,
- Смена имени на бэкенде при рефакторинге приведет к изменению ровно одного значения
В итоге данный класс будет выглядеть следующий образом
public final class BookResponse {
@SerializedName("author")
private String mAuthor;
@SerializedName("title")
private String mTitle;
}
Все готово!
Описанного выше достаточно, чтобы настроить ProGuard в вашем проекте. Как видите, ничего сложного нет, обычно 5-10 минут работы и ваше приложение как-никак, но защищено от статического анализа кода.
DexGuard
Если вам нужна только базовая обфускация и оптимизация, то ProGuard - то что вам нужно. Если же ваше приложение или библиотека требуют более серьезной защиты, следует посмотреть в сторону коммерческого DexGuard.
Возможные проблемы
- Java 8 и DexGuard: при использовании одной библиотеки, которая обфусцирована с помощью DexGuard, возникли непреодолимые трудности с использованием Java 8 еще на этапе компиляции
Оригинал статьи размещен здесь: https://dimlix.com/obfuscation_for_android/