🤖Обновили документацию по использования keep правил для R8 (минификатор кода по умолчанию)
Какие разделы теперь доступны
👉Зачем нужны keep правила
👉Глобальные правила (для всего кода) и правила для конкретного кода
👉Лучшие практики
👉Примеры использования правил
Явно задекларировали - НЕ ДЕЛАЙТЕ правило с сохранением кода всего пакета:
-keep class com.example.pkg.** { *; }
Мне не хватает описания списка всех оптимизаций кода, которые делает R8, и как писать код так, чтобы они срабатывали (например, такая особенность есть при загрузке классов через Service Loader, чтобы минификатор заменил создания через рефлексию на простой вызов конструктора)
#android#r8
🤯AI ломает R8 и восстаналивает код после защиты
Разработчик провёл эксперимент по восстановлению обфусцированного когда с помощью GPT 4o и чуда не произошло. AI смог сделать читаемые имена переменных и функций, сделать форматирование кода. С Compose кодом вообще ничего дельного не вышло. Теперь надо думать и про угрозу AI взломов усложнит жизнь IT.
Запрос на восстановление кода
Using the R8 algorithm, deobfuscate this class and translate it into its real-world context.
🔗Альтернативная ссылка на статью
#android#r8#ai
🤖Strict-режим Android Resource Shrinker — аккуратнее, он без компромиссов
В Android можно включить resource shrinking, чтобы убрать из финального APK/Bundlа неиспользуемые ресурсы (строки, drawables, layouts и т.д.)
android {
buildTypes {
release {
shrinkResources true
minifyEnabled true
}
}
}
С недавних пор Google экспериментирует со strict режимом работы шринкера, который делает эту очистку более агрессивной, а именно:
👉 Удаляет все ресурсы, которые не удалось найти в коде или XML.
👉 Не делает допущений, что ресурс “вдруг используется где-то через reflection”. Нету явного использования или keep правила - удаление
👉 Режет всё под корень — даже если вы явно используете getIdentifier() или динамически загружаете ресурсы по имени, он может их не заметить и выкинуть.
📉 Эффект - меньший размер сборки, но есть риск крешей в рантайме, если ресурсы удалены, а были нужны
Как включается strict режим:
# В gradle.properties
android.experimental.enableStrictResourceShrinking=true
🛡 Как сохранить нужные ресурсы от удаления?
Если вы точно знаете, что ресурс используется, но shrinker может его не заметить:
1️⃣ProGuard правила (R8 учитывает их для ресурсов тоже):
# Правила для R8
-keepresources R.string.some_dynamic_string
-keepresources R.drawable.icon_loaded_by_name
2️⃣Файлы в папках res/raw/ и assets/ shrinker не трогает вообще.
3️⃣tools:keep и tools:discard в XML (подробнее тут):
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/landing,@drawable/logo"
tools:discard="@drawable/unused_image" />
Рекомендации:
👉 Не включайте strict-режим без хорошего UI-тест-покрытия.
👉 Проверьте, что не используете динамическое получение ресурсов getIdentifier() без крайней необходимости.
👉 Добавляйте -keepresources, если есть малейшие сомнения.
Подробнее про оптимизацию ресурсов читайте в официальной документации
#android#r8#оптимизация
🏝Когда стоит убить Kotlin демона для ускорения сборки
Если у вас тяжёлая Android-сборка (много модулей, R8, CI с ограниченной памятью), имеет смысл принудительно завершать Kotlin Daemon после компиляции и до запуска R8 🔪
Kotlin Daemon нужен только на этапе компиляции Kotlin. После этого он спокойно живёт до конца сборки и держит память. R8 — один из самых прожорливых этапов по CPU и RAM 🔥 По итогу Daemon и R8 начинают конкурировать за ресурсы памяти
Что вы реально получаете если убивает Kotlin демона после компиляции кода:
🚀 снижение пикового потребления памяти примерно на 13–15%
🚀 ускорение R8 вплоть до ~7%
🚀 небольшое, но стабильное сокращение общего времени сборки
🚀 максимальный эффект на CI, где нет долгоживущих демонов и инкрементальности
‼️ Этот подход сработал для автора статьи, но для вас может ничем и не помочь, особенно в сборке на локальной машине.
🔗Источник с измерениями и подробным разбором
#Android#Kotlin#R8#Gradle
🤖Улучшаем работу со Stacktrace в Jetpack Compose (особенно в релизе)
Команда Compose представила opt-in API для улучшения читаемости стектрейсов во время разработки и для релизов.
Теперь становится возможным:
👉 Точно определять источник крешей в композиции, Side Effect (LaunchedEffect, DisposableEffect) и корутинах из rememberCoroutineScope.
👉 Изолировать падения для создания воспроизводимых примеров.
👉 Изучать креши, которые раньше показывали только внутренние фреймы Compose.
Достаточно добавить одну строку в точке входа в приложение (например, в Application.onCreate()):
// Включить stack trace только для минифицированных сборок (рекомендуемый способ)
Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.Auto)
// Или для локальной отладки (более точные, но тяжёлые трассировки)
Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.SourceInformation)
‼️ВАЖНО Требуется Kotlin 2.3.0, а для режимов `Auto` и `GroupKeys` - включённый R8 с минификацией.
Есть несколько режимов работы
✔️Auto (рекомендуется): использует GroupKeys для минифицированных сборок и None для отладочных.
👉GroupKeys: для минифицированных приложений. Использует маппинг-файл от R8 для восстановления примерного местоположения.
👉SourceInformation: для отладки. Даёт точные строки где произошел креш, но затратно по производительности. Стоит использовать только на этапе разработке.
❌None: ничего не добавляет (поведение по умолчанию).
Под капотом любой креш в Compose коде оборачивается в DiagnosticComposeException, который добавляется в suppressed-исключения. В нём будет полная иерархия вызовов `@Composable` функций на момент падения!
java.lang.IllegalStateException: Test layout error
at <original trace>
Suppressed: androidx.compose.runtime.DiagnosticComposeException:
Composition stack when thrown:
at ReusableComposeNode(Composables.kt:<unknown line>)
at Layout(Layout.kt:79)
at <lambda>(TempErrorsTest.kt:164) <-- Ваша функция!
... и т.д.
⚠️ Известные ограничения:
👉 В режиме SourceInformation для первых фреймов могут не указываться номера строк (<unknown line>).
👉GroupKeys указывает только на первую строку @Composable функции.
👉 Если сам сбор стектрейса упадёт, его исключение будет добавлено как suppressed.
Подробнее в официальной документации
💬 А вы уже пользовались этой фичей? Делитесь в комментариях! 👇
#AndroidDev#Kotlin#Compose#R8#Android
🤖Как удалить отладочный код в релизных сборках на примере логов
Еще одна рекомендация - используйте минификацию кода через R8/ProGuard чтобы удалить весь код логирования. Ничего лишнего не уйдёт в логи, а также повысите скорость работы
Добавьте в правила следующие инструкции
# Удаляем Log.v()
-assumenosideeffects class android.util.Log {
public static int v(...);
}
# Удаляем Log.d()
-assumenosideeffects class android.util.Log {
public static int d(...);
}
# Удаляем Log.i()
-assumenosideeffects class android.util.Log {
public static int i(...);
}
Подробнее про инструкцию assumenosideeffects читайте в документации
#android#proguard#r8#оптимизация
🤖Прячем код по-настоящему: тёмные уголки обфускации R8 и ProGuard (4м)
🤯 Знаете ли вы, что стандартная настройка ProGuard/R8 сделана для уменьшения размера сборки, а не защите приложения от реверс инжениринга?
✅Написал статью, где рассказал про то как усилить защиту, если вашему приложению это важно, а также почему даже для стандартной настройки можно сделать защиту сильнее.
🙏Буду очень благодарен если зайдёте и поддержите голосом мою статью!
#AndroidBroadcast#proguard#r8#безопасность
🤖Улучшения R8 - минификатора кода в Android
В AGP 9.0 R8 получил несколько изменений, в основном направленных на оптимизацию Kotlin-кода, упрощение desugaring-пайплайна и улучшение диагностики.
Основные изменения:
👉 Новая опция -processkotlinnullchecks для обработки null-проверок, сгенерированных компилятором Kotlin. Можно задать одно из значений:
- keep - оставить проверки;
- remove_message - убрать сообщения об ошибках;
- remove - полностью удалить проверки.
Опция используется для уменьшения байткода и снижения runtime-накладных расходов в production. Я еще в 2019 писал статью про это и удалял код с помощью -assumenosideeffects
👉 Keep rules больше не применяются к companion methods
R8 перестал переносить keep-информацию на синтетические companion-методы, сгенерированные при desugaring интерфейсов.
Это ломает редкий кейс с minSdk < 24, но делает поведение более консистентным с остальными синтетическими элементами.
👉 Минимизированные имена синтетических классов в L8
L8 теперь генерирует более короткие имена для synthetic-классов ($1, $2 вместо длинных $$ExternalSynthetic...), что уменьшает размер DEX.
L8 — это утилита, стоящая за library desugaring в Android. Позволяет использовать новые API на старых версиях Android и править баги в них, делая использование API прозрачным.
AGP 9.0 прокачало R8 и L8, чтобы делать меньше лишнего байткода, более агрессивно оптимизировать Kotlin. Большинство изменений работают прозрачно, но в сумме дают более компактные сборки и более предсказуемый build-процесс.
🔗 Источник - документация по AGP 9.0
#Android#AndroiDev#Gradle#R8
Разработчик для максимального уменьшения размера Android приложения модифировал R8, чтобы обойти ограничение на использование символов из разных регистров. На небольшом приложение вышел незначительный выигрыш. Подробности в статье
#anroid#proguard#r8
🤖 Почему ProGuard хорош, но не для Android
Решил сравнить результаты оптимизаций кода R8 с ProGuard. Не смог. Самый свежий ProGuard Gradle плагин не поддерживает Android Gradle Plugin выше 8.0 (вышел в апреле 2023) и новее. Ставлю, что платная версия DexGuard будет работать 😁
#android#безопасность#оптимищация#r8#proguard
📹 Новое видео на канале - история защиты мобильных приложений. Взлёт ProGuard
С ростом популярности мобильных приложений еще в эпоху J2ME (знаете что это вообще?) до популяризации Android смартфонов с Java технологиями неустанно вставали вопросы касательно оптимизации и защиты кода.
В новом видео рассказываю историю ProGuard - pet проекта разработчика, который стал лидером мобильной защиты, скрывающийся за стеной огромной платы.
📹 Версию на VK VIdeo смотреть тут
#AndroidBroadcast#ProGuard#защита#r8#оптимизация#производительность