Shrinkresources android что это

Обновлено: 25.04.2024

Если minifyEnabled имеет значение true, во время процесса сборки будет выполняться задача proguardRelease, вызовите метод ProguardggetDefaultProguardFile ('proguard-android.txt'), чтобы получить значение по умолчанию из proguard-android.txt в папке tools / proguard Android SDK. В настройках Proguard вы также можете указать некоторые правила для текущего модуля в proguard-rules.pro в текущем модуле.

2. Сократить ресурсы

При упаковке приложения Gradle и плагин Gradle для Android могут удалить все неиспользуемые ресурсы во время сборки. Если вы забыли удалить старые ресурсы, эта функция может оказаться очень полезной. Другой вариант использования - это импорт зависимой библиотеки с большим количеством ресурсов, но на самом деле используется лишь небольшая ее часть.Эту проблему можно решить путем активации и сокращения ресурсов. Есть два способа сократить ресурсы: автоматический и ручной.

1. Автоматически уменьшать shrinkResources

Самый простой способ - установить свойство shrinkResources в сборке. Если вы установите для этого свойства значение true, инструмент сборки Android автоматически определит, какие ресурсы не используются, и исключит их из APK. Для использования этой функции необходимо включить ProGuard. Это связано с тем, что сокращение ресурсов работает так, что до тех пор, пока в коде не будут удалены ссылки на эти ресурсы, инструмент сборки Android не может указать, какие ресурсы не используются.

Если вы хотите узнать, насколько уменьшился APK после активации автоматического сокращения ресурсов, вы можете запустить задачу shrinkReleaseResources, которая распечатает, насколько уменьшился размер пакета. Вы также можете получить обзор сокращенных ресурсов APK, добавив флаг -info после команды сборки:

Существует проблема с автоматическим сокращением ресурсов: может быть удалено слишком много ресурсов, особенно те, которые динамически используемые ресурсы могут быть случайно удалены. Чтобы предотвратить это, вы можете определить эти исключения в файле с именем keep.xml в каталоге res / raw /. Простой файл keep.xml выглядит следующим образом:

Сам файл keep.xml также будет удален из окончательного результата.

2. Ручное уменьшение resConfigs для удаления определенного языкового файла или определенной плотности изображений - лучший способ удалить ресурсы.Вы можете использовать resConfigs, чтобы ознакомиться с конфигурацией ресурсов, которые вы хотите сохранить, а остальные будут удалены.

3. Разделение APK

Разделение можно настроить, указав блок кода разделения в коде конфигурации Android. В настоящее время поддерживается разделение по плотности и разделение ABI. В разделениях поддерживаются следующие атрибуты:

Рекомендую сначала прочитать статью Playing APK Golf (или её перевод). Это крайне интересно, как исследовательская работа, но абсолютно неприменимо в реальной разработке.

Proguard

При сборке apk в его dex файл (или файлы) попадает весь код приложения и весь код всех подключенных библиотек, даже неиспользуемый. Хорошо бы от этого лишнего кода избавиться. Для этих целей есть специальный инструмент под названием proguard. Он уже включён в Android SDK и любой Android проект из коробки настроен для работы с ним. Данный инструмент делает следующее:

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

Всё это происходит на уровне Java байткода (не dex байткода), то есть файлов .class. На вход подаются jar(aar) файлы, а на выходе получаются они же, но в оптимизированном виде. В результате вес байткода значительно уменьшается.


В простейшем случае для включения proguard нужно открыть build.gradle конфиг уровня приложения и в блоке android/buildType/release выставить свойству minifyEnabled значение true:

Если в проекте есть классы, которые участвуют в рефлексии, нужно запретить их переименование, так как при попытке обращения к классам(и их свойствам и методам), которые были переименованы, приложение упадёт с исключением. Это также касается pojo(data) классов, которые маппятся, например, через Gson, Firebase Database или какой-нибудь ORM. Для того, чтобы оставить такие классы без изменений, нужно в файле proguard-rules.pro применить к ним правило -keep:

Или для всего пакета:

Со всеми правилами можно ознакомиться по ссылке.


Размер приложения уменьшился с семи мегабайт до трёх с половиной и это только за счёт оптимизации байткода. Посмотрим, что внутри через APK Analyzer:



Вот зачем это нужно. После обработки proguard код становится трудночитаемым и выглядит примерно так. Если произойдёт эксепшен, понять его стектрейс будет очень сложно. mapping.txt помогает расшифровывать эти стектрейсы так, будто код и не был обфусцирован.

Также стоит упомянуть о существовании инструмента под названием DexGuard, который оптимизирует dex байткод, но он платный и простым смертным недоступен.

shrinkResources

Теперь при сборке apk можно увидеть следующую строку:


В итоге apk уменьшился на 32 килобайта:


Не очень много, но тоже хорошо. Тут всё зависит от проекта, иногда вырезается более ощутимый объём.

Данная опция не будет работать, если в приложении есть модули Dynamic Features и\или Instant App.

Удаление ненужных языковых ресурсов

Некоторые библиотеки, особенно гугловские support lib(androidx) и firebase, содержат ресурсы для множества языков. Чтобы их удалить нужно явно указать, какие языки используются в приложении. Это делается в build.gradle уровня приложения в блоке android/defaultConfig (или в конкретном конфиге):

В моём случае это русский и английский. При сборке в apk будут включены только ресурсы для указанных языков. Посмотрим, что получилось:


Вес apk уменьшился ещё на 265 килобайт. Неплохо. Посмотрим, что внутри:


В apk остались языковые ресурсы только для русского и английского. Было 86 языков, а осталось только два.

Ещё одно средство для оптимизации байткода, но уже от гугла. Думаю, есть ненулевая вероятность того, что R8 когда-нибудь полностью заменит proguard. Этот инструмент встроен прямо в компилятор D8, который превращает Java байтод в dex байткод. В отличии от proguard, R8 работает в момент компиляции java байткода в dex байткод, что немного уменьшает общее время сборки apk.



R8 можно включить в Android Studio, начиная с версии 3.3, а с версии 3.4 он включен по-умолчанию. Для включения R8 нужно открыть файл gradle.properties и добавить строку:

Кроме этого, можно включить агрессивный режим оптимизации строкой:

Но эта функция, пока что, нестабильна и не рекомендуется к использованию.

R8 поддерживает правила для proguard (упоминавшийся ранее файл proguard-rules.pro) и точно так же генерирует файлы mapping.txt, seeds.txt и usage.txt. Кроме вырезания ненужного кода и обфускации, R8 также оптимизирует dex байткод (помним, что proguard оптимизирует только java байткод). После сборки видим, что удалось сэкономить ещё 28 килобайт за счёт уменьшения dex файла:


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

App Bundle

После сборки получается файл:


Его вес больше, чем вес apk, но это не имеет значения. По сути, это сырой файл приложения из которого могут быть сгенерированы apk файлы, которые можно устанавливать на android устройства. Этот файл загружается в Google Play Console, вместо apk, и там происходит магия. Приложение разбивается на основной apk и на набор apk конфигурации. При установке на устройство приложение собирается по частям:

При загрузке бандла в Google Play Store можно увидеть, сколько будет весить приложение:


На IO 2018 показывали такую картинку:


Для проверки и тестирования есть утилита bundletool. Она позволяет генерировать apk из бандла и манипулировать ими.

Dynamic Features

Удаление метаданных kotlin из сборки

Ещё один простой способ, подсмотренный в этой статье. В META-INF записываются дополнительные данные для рефлексии. Если в приложении не используется полноценная kotlin рефлексия(пакет kotlin-reflect), то эти файлы можно не включать в приложение. Для этого в gradle конфиге уровня приложения в блоке android нужно прописать следующее:

В моём случае вес приложения уменьшился ещё на 412 килобайт. Здесь показатель уменьшения веса напрямую зависит от количества кода в приложении. После сборки приложения стоит убедиться, что ничего не поломалось, так как рефлексия может использоваться в подключенных библиотеках. Также можно исключать отдельные файлы, чтобы оставить нужные для рефлексии.

И это ещё не всё

Gradle — система автоматической сборки, построенная на принципах Apache Ant и Apache Maven. В Eclipse использовалась система Ant, но большинство разработчиков даже не замечало её работы. В основном возможности системы использовались в конторах для автоматизации различных задач. В Android Studio такой номер не пройдёт. Gradle сопровождает вас во время разработки постоянно. Поначалу, если вы перешли с Eclipse, Gradle сильно раздражает своими действиями. Но позже вы оцените её удобство и может даже полюбите её.

Gradle не является изобретением для Android Studio, система была разработана раньше и использовалась в приложениях для Java, Scala и других языках.

Система сборки Gradle очень мощная и сложная, чтобы о ней рассказать в двух словах. Есть целые книги о ней. Сами команды в Gradle представляют собой обычный текст с использованием синтаксиса Groove для конфигурации. Но нам не нужно знать всё. Познакомимся поближе с системой и научимся пользоваться ей.

Создайте новый проект или откройте любой существующий проект из Android Studio и посмотрите на структуру проекта.

В последних версиях студии файлы Gradle выделили в отдельную папку Gradle Script. Раскройте её. В основном вас должен интересовать файл build.gradle, который относится к модулю. Рядом с этим файлом в скобках будет написано Module: app. Двойным щелчком откройте его, вы увидите, что файл является текстовым.

Также есть файл build.gradle, который относится к проекту. Но с ним работают реже. Так находятся настройки для репозиториев и самого Gradle.

Вернёмся к файлу модуля, вы увидите много интересной информации. Например, вы там можете увидеть настройки, которые раньше вы могли видеть в манифесте - номера версий, номера SDK и так далее. Забегая вперёд, скажу, что здесь можно добавить всего одну волшебную строчку и нужная библиотека сама скачается из интернета и установится в проекте. Красота!

Однако вернёмся в корневую папку. Кроме файлов build.gradle мы можем заметить файлы gradle.properties, settings.gradle и другие. Трогать их не нужно.

Вы могли заметить, что по сравнению с Eclipse изменилась структура файлов. В папке app находится папка src, а ней папка main, в которых папки java, res и файл манифеста. Новая структура лучше отвечает требованиям Gradle для управления файлами.

Вы, например, можете создавать альтернативные папки с ресурсами и с помощью build.gradle подключить их к проекту.

В этом примере мы указали, что существуют новая папка presentations в папке /src/main/ наряду с существующими папками java и res. Внутри созданной папки есть ещё две папки layout и animations, которые содержат файлы ресурсов.

Только помните, что вам нужно избегать конфликта имён при слиянии всех файлов при сборке.

Значение sourceSets указывает Gradle, какие папки следует использовать. Этим приёмом пользуются продвинутые программисты. Мы пока не будем использовать такую технику.

Другая полезная возможность - создавать разные версии приложений, например, демо-версию и платную версию. Немного об этом рассказано здесь.

Номер версии приложения и требования к версии Android прописаны в секции defaultConfig. Если у вас сохранились старые версии приложений, то в манифесте можете удалить данные записи. По-моему, там даже выводится соответствующая подсказка. Даже если вы эти данные в манифесте не удалите, то значения из gradle.build имеют больший приоритет и перепишут значения в манифесте при не совпадении.

Подключение библиотеки происходит одной строчкой. Например, нужно добавить библиотеку Picasso:

В Android Studio 3.0 используется новая версия Gradle, в которой compile считается устаревшей. Вместо него следует использовать новое слово implementation.

Есть похожая команда, которая подключает библиотеку, которая будет использоваться только для отладки приложения и в релизной версии она не нужна.

Далее включаете синхронизацию и через несколько секунд в папке появляется нужная библиотека, готовая к использованию. Сама библиотека скачивается с специального хранилища-репозитория JCenter. Данный репозиторий используется по умолчанию и прописан в buil.gradle проекта.

Можно указать другой репозиторий, например, Maven Central.

Для поиска через Maven-репозиторий используйте The Central Repository Search Engine.

Библиотеку можно подключать и старым способом, используя jar-файл, но такой способ уходит в прошлое.

Сам файл нужно скопировать в папку <moduleName>/libs.

При любом изменении файла недостаточно его сохранить. Нужно также произвести синхронизацию. Наверху обычно появляется жёлтая полоска с ссылкой Sync Now.

Задаём имя APK при компиляции

Можно задать собственное имя при компиляции проекта. Например, так.

Получим имя MyName-1.0.12-release.apk

Оптимизатор кода R8

Оптимизатор кода R8 имеет следующие возможности: урезание байт-кода, сжатие, обфускация, оптимизация, удаление «синтаксического сахара», преобразование в DEX. Оптимизатор может производить все операции за один шаг, что даёт сильное улучшение производительности. R8 был введён в Android Gradle plugin 3.3.0. Вам нужно только включить его.

R8 разработан для работы с существующими ProGuard-правилами, хотя возможны ситуации, когда нужно переработать правила.

Сжимаем итоговый APK

В Gradle 1.4 появилась возможность сжать итоговый файл, убрав неиспользуемые ресурсы, в том числе из библиотек, например, Google Play Services.

Во время сборки приложения вы можете увидеть строку:

Другой способ убрать неиспользуемые ресурсы конфигурации. Например, вам не нужные локализованные ресурсы для всех языков, которые входят в библиотеку Google Play Services или Android Support Library и др. Оставим только нужные языки. Возможно, вы также не хотите поддерживать mdpi или tvdpi-разрешения в своём приложении. Мы можем установить языки и разрешения, которые используются в приложении, остальные будут исключены, что позволит уменьшить вес приложения.

Можно перенести ключи из манифеста.

Чтобы их не светить, например, если выкладывать код на Гитхабе, то сделаем так.

И в манифесте переделаем код.

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

В манифесте пишем.

Класс BuildConfig

В статье LogCat упоминался способ быстрого отключения журналирования.

Суть в следующем. Когда вы создаёте новые переменные в блоках defaultConfig или buildTypes (ветки debug и release), то Gradle создаёт специальный класс BuildConfig, и вы можете получить доступ к этим переменным.

Например, добавим переменную в defaultConfig

На языке Java это равносильно String YOUR_TOKEN = "ABRAKADABRA";

Теперь мы можем обратиться к созданной строке.

С секцией buildType ситуация интереснее. У секции есть два блока debug и release. Можно создать переменные с разными значениями, которые будут использоваться в зависимости от ситуации. Например, у вас есть собственное API для сервера. Для тестирования вы используете один адрес, а для финальной версии - другой адрес. Тогда вы просто указываете разные адреса в разных ветках. Переменные могут быть не только строковыми.

Создаём код для перехода на веб-страницу.

Теперь вам не нужно переписывать каждый раз код. Загружаться будет страница по нужному адресу автоматически.

Разделяем отладочную и финальную версию

По такому же принципу можно организовать запуск новой версии программы, не затрагивая программу, которую вы установили с Google Play. Допустим вы на своём телефоне установили своё собственное приложение через Google Play. Теперь вам нужно написать новую версию и проверить на своём телефоне. Из-за конфликта имён новое тестируемое приложение перепишет финальную версию или вообще не установится. Поможет следующий трюк.

В специальных переменных applicationIdSuffix и versionNameSuffix мы задаём суффиксы, чтобы избежать конфликта. А в переменной resValue указываем название программы для отладочной и финальных версий, чтобы на устройстве можно было их найти. Не забудьте при этом удалить строковый ресурс app_name в res/values/strings.xml, иначе получите ошибку при компиляции. Теперь можете спокойно запускать приложение с новым кодом, не боясь повредить своё любимое приложение.

Прячем секретную информацию

Следующий совет больше подходит для компаний. Когда подписывается приложение, то нужно указывать пароль, хранилище и т.д. Чтобы их не светить в студии, можно прописать их в переменных и поместить в секцию signingConfigs. Сервер сам найдёт нужные ключи и воспользуется ими в своих сценариях.

Автогенерация версии кода

Нашёл совет, сам не применял. Не обязательно вручную менять версию приложения в атрибутах versionCode и versionName, можно сделать через переменные, а они сами подставятся в нужное место. На любителя.

settings.gradle

Файл settings.gradle обычно состоит из одной строчки.

Это означает, что у вас используется один проект для работы. Если вы будете подключать другие проекты, то здесь появятся новые строки.

gradle.properties (Project Properties)

Несколько советов по настройке файла gradle.properties.

Режим параллельного выполнения

Gradle-демон

Включение на компьютере демона Gradle даст значительный прирост в скорости сборки.

Режим конфигурации при необходимости

Если в проекте используется много модулей, то можно включить режим конфигурации при необходимости. Ускорение будет заметно при большом количестве используемых модулей:

Меняем номер версии библиотек в одном месте

Очень часто в проекте используются взаимосвязанные библиотеки с одинаковыми номерами.

Можно быстро поменять у всех номера через переменную. Для этого используется секция ext, в которой указывается переменная и номер версии. Затем в секции dependencies номер версии заменяется на имя переменной

Обратите внимание, что одинарные кавычки заменяются на двойные, а символ $ указывает на строковый тип.

Расширенная версия с разными переменными в другом виде.

Если в проекте используются несколько модулей с одинаковыми зависимостями, то эти записи можно перенести в корневой build.gradle, чтобы не менять номера версий в каждом модуле.

Настройки в Android Studio

Рассмотрим настройки, доступные в Android Studio. Закройте текущий проект, чтобы увидеть стартовое окно студии. В правой части нажмите на пункт Configure. В следующем окне выберите пункт Settings, чтобы оказаться в окне настроек студии. В левой части найдите пункт Build, Execution, Deployment, затем подпункт Build Tools, далее подпункт Gradle. По умолчанию, там всё чисто, только указан путь у Service directory path. Это были общие настройки.

Теперь рассмотрим настройки, относящиеся к проекту. Запустите любой проект в Android Studio. Выберите меню File | Settings. . Снова пройдитесь по пунктам Build, Execution, Deployment | Build Tools | Gradle. Вы увидите практически такое же окно с небольшими изменениями. Теперь поле Linked Gradle Projects не будет пустым, а также появятся дополнительные настройки. По умолчанию рекомендуют использовать Use default gradle wrapper.

Gradle Task

На правой стороне Android Studio имеется вертикальная вкладка Gradle, которую можно развернуть. Она содержит список задач (task), которая выполняет Gradle при работе с текущим проектом. Вы можете выделить любую из этих задач и запустить её двойным щелчком. Можно выделить несколько задач.

Gradle Console

Когда выполняется какая-то задача Gradle, то ход её выполнения можно увидеть в окне Gradle Console. Открыть её можно через вкладку Gradle Console в нижней правой части студии.

Terminal

Запускать задачи Gradle можно и в окне Terminal.

Добавление зависимостей через интерфейс студии

В статье описывался способ включения библиотеки в проект через редактирование файла build.gradle. Существует альтернативный вариант через настройки студии. Щёлкните правой кнопкой мыши на имени модуля (app) и выберите пункт Open Module Settings (быстрая клавиша F4). В правой части окна находятся вкладки, которые оказывают влияние на файл build.gradle. Например, вкладка Dependencies содержит подключаемые библиотеки.

Чтобы добавить новую зависимость, нажмите на значок с плюсом и выберите нужный вариант, например, Library dependency. Откроется список доступных библиотек из репозитория Maven.

Дополнительное чтение

В примере работы с PDF-файлами в папке assets использована операция запрета на сжатие файлов, которое происходит по умолчанию.

Согласно веб-странице "Сокращение ресурсов" документации Andriod ( здесь ), вы можете минимизировать размер приложения с помощью файла build.gradle, используя следующие строки:

И они говорят, что при использовании он также скажет вам, сколько сэкономлено в процессе:

Когда вы включаете shrinkResources, сборка вашего приложения должна отображать вывод, подобный следующему во время сборки:

. Удалены неиспользуемые ресурсы: данные двоичных ресурсов уменьшены с 2570 КБ до 1711 КБ: удалены 33%

Вопросы

Я не могу найти ответы на эти вопросы:

  1. При использовании самой Android-Studio для создания подписанного приложения, где я могу найти информацию о том, сколько было сохранено и какие файлы были удалены/изменены?
  2. Что именно "shrinkResources" делает, а "minifyEnabled" - нет? И почему "shrinkResources" зависит от "minifyEnabled"?
  3. Влияет ли какая-либо из этих опций на размер и/или качество файлов изображений?
  4. Разве Proguard не несет ответственность за сокращение исходного кода? Я спрашиваю об этом, потому что он говорит: "Вы должны включить minifyEnabled, чтобы включить сжатие кода".

При использовании самой Android-Studio для создания подписанного приложения, где я могу найти информацию о том, сколько было сохранено и какие файлы были удалены/изменены?

Это будет в журнале. Внутри Android студии, я думаю, они отображаются в окне Messages (рядом с окнами Android, Run, TODO).

Что именно "shrinkResources" делает, а "minifyEnabled" - нет? И почему "shrinkResources" зависит от "minifyEnabled"?

minify запускает ProGuard. shrink удалить ресурсы, которые ProGuard пометил как неиспользуемые.

Влияет ли какая-либо из этих опций на размер и/или качество файлов изображений?

Разве Proguard не несет ответственность за сокращение исходного кода? Я спрашиваю об этом, потому что он говорит: "Вы должны включить minifyEnabled, чтобы включить сжатие кода".

ProGuard сокращает ТОЛЬКО КОД ; shrinkResources это просто материал из папки /res/ . shrinkResources зависит от вывода журнала ProGuard для запуска. ProGuard - это тот, кто на самом деле анализирует код, чтобы узнать, что не используется.

редактировать:

это прекрасно объясняет ваш следующий вопрос:

почему один зависит от другого?

Proguard работает на стороне Java. К сожалению, это не работает на стороне ресурсов. Как следствие, если изображение my_image в res/drawable не используется, Proguard только удаляет его ссылку в классе R, но сохраняет связанное изображение на месте.

это означает, что shrinkResources сравнивается только в том случае, если объект рисования находится в папке, но не в классе R .

Ответы на вопросы 2 и 4 можно найти в этом видео из Android Dev Summit 2015 вместе с другой полезной информацией по этой теме.

Читайте также: