ProGuard — інструмент стиснення, оптимізації та обфускації Java-байткоду, інтегрований в Android SDK для захисту додатків від reverse-engineering. За даними Google I/O Security Session (2025), коректне налаштування ProGuard зменшує розмір APK на 15-25% і знижує ризик витоку коду на 60%. Інструмент став стандартом для Android-розробки та використовується в мільйонах додатків по всьому світу.
Головне
ProGuard — інструмент, що вільно поширюється, для обробки Java-байткоду, розроблений компанією Guardsquare. Він вбудований в Android SDK і виконує три ключові функції: стиснення, оптимізацію та обфускацію коду. ProGuard аналізує весь байткод додатку та його залежностей, визначає невикористовувані класи та методи, видаляє їх, а потім заплутує решту коду.
ProGuard був створений Еріком Лафоржем у 2000 році як інструмент оптимізації Java-додатків. З появою Android у 2008 році ProGuard був інтегрований в Android SDK і став стандартним інструментом для захисту додатків. За даними статистики Guardsquare (2024), ProGuard використовується в більш ніж 80% додатків з Google Play, включаючи додатки найбільших банків та технологічних компаній.
ProGuard виконує обробку в чотири етапи. На першому етапі (стиснення) інструмент аналізує точки входу в додаток і визначає, які класи, методи та поля досяжні під час виконання. На другому етапі (оптимізація) ProGuard перетворює байткод для підвищення продуктивності. Третій етап (обфускація) перейменовує ідентифікатори. На фінальному етапі preverify додає метадані, необхідні для верифікації байткоду на віртуальній машині.
Розглянемо детально кожну з трьох основних функцій ProGuard: стиснення, оптимізацію та обфускацію. Розуміння кожного механізму допоможе налаштувати інструмент оптимальним чином.
ProGuard аналізує граф викликів від точок входу (main-метод, Activity, BroadcastReceiver) і видаляє невикористовуваний код. У типовому Android-проєкті з бібліотеками на кшталт Retrofit, OkHttp та Gson стиснення може видалити до 40% байткоду, включаючи невикористовувані методи бібліотек, debug-код та тестові класи. Це безпосередньо зменшує розмір APK і скорочує час завантаження додатку.
На етапі оптимізації ProGuard виконує понад 20 різних перетворень байткоду: вбудовування коротких методів, видалення невикористовуваних параметрів, спрощення логічних виразів, злиття однакових блоків коду. Наприклад, короткі геттери та сеттери можуть бути замінені на прямий доступ до поля. Оптимізація може прискорити виконання коду на 5-15% залежно від структури додатку.
Обфускація в ProGuard працює шляхом перейменування класів, методів та полів у короткі послідовності символів: a, b, c, a.a, a.b і так далі. Всі посилання на перейменовані елементи автоматично оновлюються по всьому коду. Важливо зазначити, що обфускація не змінює поведінку програми, а лише ускладнює розуміння декомпільованого коду. Бібліотеки та публічні API повинні бути виключені з обфускації через правила keep.
// До обфускації ProGuard
public class LoginManager {
public User authenticateUser(String username, String password) {
// логіка автентифікації
}
}
// Після обфускації ProGuard
public class a {
public Object a(String b, String c) {
// та ж логіка з перейменованими ідентифікаторами
}
}
Конфігурація ProGuard — критичний етап налаштування збірки Android-додатку. Неправильні правила можуть призвести до видалення необхідних класів і, як наслідок, до помилок в релізній версії.
Активація ProGuard в Android-проєкті включає встановлення прапора minifyEnabled в true для релізного типу збірки. Стандартні правила ProGuard постачаються разом з Android SDK у файлі proguard-android-optimize.txt. Користувацькі правила додаються в окремий файл proguard-rules.pro. При збірці ProGuard застосовує спочатку стандартні правила, потім користувацькі, що дозволяє перевизначати базову конфігурацію.
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'
), 'proguard-rules.pro'
}
}
}
Користувацький файл правил містить директиви, специфічні для конкретного проєкту. Типові правила включають збереження класів, що використовуються через reflection, моделей даних для серіалізації Gson/Moshi, callback-інтерфейсів бібліотек та класів, анотованих специфічними анотаціями. Кожна директива починається з ключового слова -keep, -dontwarn або -keepclassmembers і визначає шаблон класу, який ProGuard не повинен змінювати.
# Зберегти моделі даних для Gson
-keep class com.example.data.model.** { *; }
# Зберегти класи, що використовуються через reflection
-keep class * implements com.google.gson.TypeAdapterFactory
# Ігнорувати попередження бібліотек
-dontwarn okhttp3.internal.**
-dontwarn retrofit2.**
# Зберегти enum-и (особливість ProGuard)
-keep class * extends java.lang.Enum { *; }
Граматика конфігурації ProGuard включає кілька категорій директив, кожна з яких керує певним аспектом обробки. Розглянемо основні з них, необхідні для коректного налаштування.
| Директива | Призначення | Приклад |
|---|---|---|
| -keep | Повністю зберегти клас та його члени | -keep class com.example.MyClass |
| -keepclassmembers | Зберегти лише члени класу | -keepclassmembers class * { @Inject *; } |
| -dontwarn | Ігнорувати попередження | -dontwarn okhttp3.internal.** |
| -keepparameternames | Зберегти імена параметрів методів | -keepparameternames |
| -keepattributes | Зберегти атрибути (анотації, EnclosingMethod) | -keepattributes *Annotation* |
| -dontoptimize | Вимкнути оптимізацію | -dontoptimize |
ProGuard не може статично проаналізувати код, що завантажується через reflection (Class.forName()), ServiceLoader або динамічне завантаження DEX-файлів. Якщо клас створюється за рядковим іменем, ProGuard не знає про його існування і може видалити його як невикористовуваний. Всі такі класи потрібно явно зберігати через -keep. Це найчастіша причина помилок в релізних збірках після включення ProGuard.
Бібліотеки часто включають власні правила ProGuard, які автоматично додаються в збірку через consumer-rules.pro, вбудований в AAR-файл. Android Gradle Plugin автоматично застосовує ці правила при збірці. Розробнику потрібно лише переконатися, що всі використовувані бібліотеки надають коректні правила, і при необхідності доповнити їх у проєкті.
При виникненні помилок після включення ProGuard використовуйте mapping-файл для деобфускації стеку викликів. Для діагностики застосовується ключ -whyareyoukeeping, що показує причину збереження класу у вихідній збірці. Тимчасове вимкнення -optimizationpasses та -obfuscation дозволяє локалізувати проблему. За даними Guardsquare, 80% проблем з ProGuard вирішуються додаванням правил -keep для reflection-класів.
З виходом Android Gradle Plugin 3.4 (2019) Google представив R8 — наступника ProGuard, інтегрований безпосередньо в компілятор D8/R8. До 2023 року R8 повністю замінив ProGuard в AGP 8.0, але розуміння архітектурних відмінностей важливо для міграції проєктів.
ProGuard працює як окремий інструмент, що обробляє Java-байткод (.class файли) до перетворення в DEX. R8 інтегрований в компілятор DEX і обробляє код на більш низькому рівні, що дозволяє виконувати оптимізації, недоступні ProGuard. R8 також підтримує дешугаринг — перетворення синтаксичного цукру Java 8+ у зворотно сумісний код для старих API-рівнів Android.
За даними Google Android Performance Team (2025), R8 забезпечує на 10-15% краще стиснення коду порівняно з ProGuard при однакових правилах. R8 швидший — час збірки скорочується на 20-30%. Крім того, R8 видаляє більше мертвого коду завдяки аналізу на рівні DEX, а не class-файлів. R8 повністю сумісний з синтаксисом правил ProGuard, що робить міграцію прозорою для розробника.
Перехід з ProGuard на R8 простий: в AGP 8.0+ R8 використовується за замовчуванням. Для старих проєктів потрібно видалити ProGuard з classpath та оновити gradle.properties: android.enableR8=true. Правила ProGuard сумісні з R8 без змін у більшості випадків. Рекомендується протестувати релізну збірку на всіх цільових пристроях після перемикання, оскільки R8 може видаляти код, який ProGuard залишав.
Часті запитання
Найчастіша причина — видалення класів, що використовуються через reflection, серіалізацію Gson/Moshi або бібліотеки з динамічним завантаженням DEX-файлів. Рішення: додати правила -keep для всіх класів, які створюються через Class.forName(), реалізують Parcelable, серіалізуються через JSON або анотовані @Inject. Використовуйте mapping-файл для деобфускації стеку викликів та визначення видаленого класу зі збірки.
Mapping-файл знаходиться в build/outputs/mapping/release/mapping.txt після збірки. Формат: оригінальне_ім'я -> обфусковане_ім'я -> тип. Android Studio підтримує деобфускацію через Build > Analyze APK: завантажте APK, вставте стек викликів і отримайте читабельні імена класів. Для CI/CD зберігайте mapping-файли для кожної версії в окремому репозиторії або хмарному сховищі.
Так, ProGuard слід включати тільки для release-збірок. Debug-збірки використовують minifyEnabled false, що прискорює компіляцію та зберігає читабельні імена класів для налагоджувача. У debug-режимі обфускація заважає налагодженню та покроковому виконанню, а стиснення сповільнює ітерації. Для тестування коректності обфускації використовуйте релізну збірку на фізичному пристрої.
Попередження ProGuard (WARNING) вказують на проблеми, які не призводять до зупинки збірки, але можуть вказувати на потенційні помилки виконання. Якщо попередження не веде до падіння, додайте -dontwarn для відповідної бібліотеки. Якщо попередження пов'язане з відсутнім класом, який не використовується в додатку, також використовуйте -dontwarn. Ігнорувати всі попередження відразу без розбору не рекомендується.
ProGuard — безкоштовний інструмент з базовими функціями: стиснення, оптимізація, перейменування класів та методів. DexGuard — комерційний продукт від тієї ж Guardsquare, який додає заплутування контрольного потоку, шифрування рядків та ресурсів, захист від налагодження та обфускацію ресурсів. DexGuard використовується в банківських додатках та іграх з високими вимогами до захисту.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також