как уменьшить вес приложения на андроид
Уменьшаем размер приложения: проверенные способы
Введение
Одним из немаловажных аспектов разработки мобильных приложений является оптимизация размера. Мы все по личному опыту знаем, что чем меньше весит приложение, тем охотнее его скачивают, особенно если под рукой нет точки доступа Wi-Fi, а скорость и/или трафик мобильного интернета оставляют желать лучшего. К тому же, нельзя забывать и о том, что некоторые маркеты ставят ограничение на размер выпускаемого приложения. Например, в App Store продукты размером до 100 МБ доступны для скачивания по мобильному интернету, если же вес приложения превышает этот порог, то скачать его можно только через Wi-Fi. На Play Market же приложение, которое вытягивает больше 100 МБ, нельзя загрузить в принципе. В данной статье мы опишем, к каким методам и хитростям прибегали наши разработчики нативных приложений на iOS для того, чтобы уменьшить вес продукта, и добавим к этому несколько дельных советов, найденных в сети.
Основные способы уменьшения размера приложения
Графический контент
Сейчас дизайн играет ключевую роль в любом хорошем приложении. Если интерфейс минималистичен или продукт имеет небольшой набор функций, то этот этап можно пропустить. Если же проект отличается богатым функционалом или поддерживает некоторое количество цветовых схем, то здесь уже не обойтись без большого количества изображений со всеми вытекающими последствиями для веса. Кроме того, зачастую в проекты по умолчанию добавляются наборы изображений под различные форм-факторы мобильных устройств, как например @1x, @2x, @3x для iOS приложений. Ниже мы приведем методы, которые использовали в своих приложениях, чтобы разрешить проблему с обилием графического контента. Возможно, какие-то из них вы применяете и сами.
Один из простейших путей — использовать вместо трех масштабов только 3x изображение. Этот способ не назовешь оптимальным, так как на устройствах, ориентированных под 1x и 2x масштабы, такие изображения не всегда будут смотреться приемлемо. Однако за неимением лучшего этим приемом можно неплохо уменьшить размер проекта при огромном количестве графики.
Другой способ завязан на добавлениеи векторных изображений вместо растровых. На iOS мы экспортировали изображения в формат PDF. Зачастую такой файл действительно весит меньше, однако это работает не со всеми изображениями. Загвоздка здесь в том, что в векторная графика может некорректно отображать некоторые маски изображения, делая их абсолютно черными или искажая цвета.
Теперь рассмотрим пример с приложением, имеющим несколько цветовых схем (в простонародье «скин»). Чем больше цветовых схем в приложении, тем сильнее возрастает количество необходимых изображений. Если в изображении используется более одного цвета, то приходится хранить несколько вариантов на каждый скин. Однако, в случае когда изображение однотонное, его можно сделать шаблонным и уже в самом коде менять цвет оттенка (tint color). На iOS создать подобный шаблон можно двумя способами:
Рис.1. Выставление шаблонного режима изображения в XCode.
— где UIImageRenderingModeAlwaysTemplate и является шаблонным режимом изображения.
Замена анимационных изображений
Добавление анимации — обычное дело в приложениях. Она привлекает внимание пользователя к нужным объектам интерфейса и делает его менее статичным, обеспечивая более приятный опыт взаимодействия. Некоторые простые анимации, наподобие перемещения объекта из одной части экрана в другую или появления снизу нового окна, можно сделать программно. Другие же, более сложные, требуют отрисовки каждого кадра анимации. Когда мы впервые столкнулись с добавлением анимационного изображения в ходе разработки, то использовали для его реализации один из распространенных способов, а именно анимирование через массив изображений. Выглядело это так:
Сначала создается массив с названиями изображений, затем — массив который поочередно пополняется изображениями из названий. Потом у переменной типа UIImageView задаются массив изображений для анимации, продолжительность анимации и количество повторений. После чего запускается сама анимация. Однако если кадров много и при этом на каждый из них приходится по три масштаба, то для размера приложения это не сулит ничего хорошего. Придя к такому печальному итогу, мы задались поиском способа добавления gif-файла вместо массива картинок. К счастью, на просторах интернета нам попалась категория UIImage+animatedGIF, которая все это уже умеет. Данная категория добавляет классу UIImage два метода:
Первый метод загружает gif, сохраненный в виде данных, а второй метод берет его прямо из ссылки на ресурс, например, из бандла приложения. Сам gif-файл можно сделать из тех же кадров на каком-нибудь сервисе для создания таких файлов, где задается количество кадров в секунду, сжатие и разрешение. Правильно выставленные параметры дадут на выходе гифку приемлемого веса. Теперь остается только добавить ее в бандл и использовать один из методов указанных выше.
Однако gif-файл тоже занимает пространство, поэтому мы старались выполнить все анимации программно. В Audio Editor Tool на стартовом экране у нас проигрывается анимация появления логотипа AUDIO EDITOR побуквенно. Раньше данная анимация была реализована с помощью гифки, но из-за большого разрешения изображения весила она многовато. Поэтому мы решили реализовать ее с помощью CABasicAnimation.
Чтобы логотип у нас появлялся побуквенно, как на гифке, мы использовали градиентную маску, которая со временем смещала начальную позицию прозрачности. Для начала мы создали слой градиента, у которого прозрачный цвет идет практически с самого начала. Потом задали градиент как маску слоя текста логотипа, тем самым делая его прозрачным. Следующим шагом создали группу анимаций, в которую добавили две анимации. Первая из них смещала начальную позицию градиента, а вторая — конечную, тем самым делая его непрозрачным. Отметим один нюанс: важным шагом было указать в свойстве removeOnCompletion отрицательное значение, иначе анимация была бы удалена по завершению и слой вернулся бы к начальному значению.
Конвертирование аудио
В наших приложениях часто используются аудиофайлы формата WAV. В силу своей структуры этот формат занимает много места в проекте. По этой причине было решено сначала полностью заменить в бандле все файлы этого формата на более легковесный M4A, а потом, уже в самом приложении, конвертировать их в WAV. Почему бы просто не использовать M4A? Потому, что при цикличном воспроизведении файла этого формата происходит задержка при начале каждого цикла, будто там присутствует некая пустота. Завершающий шаг — сохранить уже конвертированный файл в директории приложения после первого запуска.
В данном методе берется файл из бандла по url и сохраняется в директорию по convertedUrl. Считываемый файл загружается в буфер и уже оттуда записывается в новый с требуемыми настройками записи. Таким образом, мы используем более стабильный и тяжеловесный WAV после первого запуска, но при этом размер приложения существенно уменьшается на этапе загрузки и установки.
Подгрузка файлов с сервера
Подгрузка файлов с сервера — это то что нужно для приложений со значительным объемом контента. Большое количество пресетов музыки, наборы изображений и многое другое, что сильно увеличивает размер приложения, можно загрузить и позднее. Конечно, загрузка каждого отдельного файла потребовала бы много времени и трафика, поэтому с сервера подгружаются архивы со всем необходимым, а уже в самом приложении они распаковываются и сохраняются в директории приложения. Для разархивирования используется библиотека SSZipArchive (репозиторий библиотеки вы найдете по ссылке). Эта библиотека способна как упаковывать файлы в архив, так и распаковывать архивы. Но нас интересует только один метод из основного класса библиотеки:
Данный метод распаковывает файл из пути path в путь destination, а пока он распаковывается в progressHandler можно совершать какие-либо действия (например, отображение прогресса распаковки), после чего в completionHandler показать, что распаковка благополучно завершилась, либо вывести ошибку при неудаче.
Заключение
41 МБ, а после загрузки всех пресетов — 281 МБ, то описанные методы смогли уменьшить размер приложения примерно в семь раз. Результат неплохой, хотя, возможно, существуют и более актуальные способы. Если вы знаете о таких, предлагаем поделиться в комментариях.
UPD: Спасибо Dim0v за дельные замечания о графическом контенте. Приводим их ниже:
«Во-первых, для устройств с iOS 9 и выше работает App slicing. iTunes Connect пересобирает загруженный архив в несколько вариантов для разных устройств. Таким образом, например, iPhone 6 при установке из апп стора будет тянуть только @2x ресурсы, а iPad mini 1 — только @1x. Поэтому если продукт поддерживает iOS 9+, то прислушивание к совету об оставлении только 3x ресурсов будет иметь строго обратный эффект — для айфонов+ ничего не изменится, а вот устройства с меньшим разрешением будут вынуждены тянуть себе 3x ресурсы, тогда как могли обойтись 2x или 1x.
Во-вторых — совет о переводе растровых изображений в вектор также не имеет смысла. Единственное, что вы таким образом можете сэкономить — это место на компьютере разработчиков. Xcode растеризирует векторные изображения при сборке билда, в чем несложно убедиться, к примеру, отмасштабировав «векторную» картинку на устройстве и увидев дико пикселизированное растровое изображение. Я не спорю, векторные ресурсы — это удобно: проще экспортировать дизайнерам, не нужно следить чтобы при изменении ресурса остались «синхронизированными» все его версии разных разрешений и т.п. Но перевод существующих растровых картинок в вектор именно с целью уменьшения размера билда не имеет никакого смысла».
Сжимаем несжимаемое – как уменьшить дистрибутив мобильного приложения
Сегодня в магазинах приложений для платформ iOS и Android существует ограничение на размер приложения в 100 МБ. Магазин Apple для приложений, которые не укладываются в этот лимит, запрещает закачку при помощи мобильного интернета. В Google Play же это строгий лимит на размер APK – все, что не укладывается в него, должно быть вынесено в файлы дополнений. Для пользователей с платным трафиком закачка большого приложения может быть довольно затратной, поэтому его размер нужно стараться уменьшить всеми силами.
Формат магазина приложений Apple
Большую часть занимают ресурсы игры, при этом исполняемый файл почти не уступает им. Системные ресурсы и ресурсы SDK при этом занимают достаточно мало места в архиве, поэтому оптимизировать их чаще всего нет смысла.
Оптимизация размера исполняемого файла
Исполняемый файл занимает так много места по двум причинам:
Пункт 2 актуален всегда. При расчете предполагаемого размера IPA нужно учитывать несжатый размер исполняемого файла. В лучшем случае он сожмется только незначительно. Именно поэтому Apple не рекомендуют хранить большие объемы данных (изображения, большие текстовые ресурсы и т.д.) в исполняемом файле, это может привести к аномально большому размеру приложения. Стоит также проверить настройки оптимизации в XCode и убедиться в том, что вы не подключаете лишние библиотеки.
Оптимизация ресурсов
Для мобильных игр можно выделить группы ресурсов, по списку от более тяжеловесных к менее тяжеловесным:
Сжатие игровой графики
Размер графики можно уменьшить двумя способами:
Во-вторых, pvrtc – это lossy-формат, и даже очень lossy. Его нужно применять осторожно, не стоит использовать с графикой, для которой требуется высокое качество. Плохо подходит для графики с прозрачными областями, на границе будут артефакты. Основная выгода от формата pvrtc – экономия оперативной памяти. В отличие от форматов png и webp, его не нужно распаковывать в RGBA для отрисовки.
Не стоит забывать о том, что у сжатых форматов есть свои настройки качества, и их тоже можно настраивать.
Webp 100 | Webp 95 | Webp 85 |
Пример сжатия
Пример одного и того же изображения в формате webp, сжатого с настройкой качества 85, 95 и 100. Разница заметна, но даже самое сжатое изображение выглядит приемлемо. При этом разница в размере между webp85 и webp95 примерно 3 КБ.
webp нужно применять осторожно из-за проблем со скоростью распаковки. На медленных устройствах загрузка такого изображения может дать заметные лаги. Не стоит использовать его для упаковки большой графики, которая подгружается на лету.
В таблице приведены размеры атласа 2048×2048 при сжатии в разных форматах:
Формат | png | pvrtc | webp lossless | webp 95 quality | webp 85 quality |
Размер, КБ | 8057 | 2049 | 5593 | 2218 | 1579 |
Как видите, формат png не следует использовать вообще. Из форматов webp и pvrtc можно выбрать подходящий, с учетом требований к качеству графики и скорости ее загрузки
Анимации
Видео и звуки
Здесь нет каких-то общих рекомендаций, в целом все сводится к тонкой настройке форматов кодирования. Какого-то феноменального выигрыша тут получить нельзя, у нас получилось сжать видео на примерно 30% по сравнению с первоначальным вариантом и сэкономить порядка 10-20% на звуках. Все зависит от конкретного видео и аудио – нужно подбирать настройки экспериментально.
Шрифты
Обычно, шрифты не занимают много места в большинстве приложений. Но это пока вы не столкнетесь с локализациями для языков с иероглифическим письмом. Число иероглифов там может измеряться тысячами. Это увеличивает файлы шрифтов до нескольких мегабайт. Чтобы бороться с этим, мы используем автоматизированный скрипт, который составляет списки символов на основе файла с игровыми текстами – все неиспользуемые символы удаляются изо всех шрифтов.
Текстовые ресурсы и текстовые настроечные файлы
Это обычно самая малая по размеру группа ресурсов, и ее не нужно отдельно оптимизировать. Сам ipa-файл это архив, а текстовые данные хорошо архивируются. В нашем проекте тексты тем не менее занимают довольно много места. В основном из-за необходимости поддержки многих локализаций.
Если все возможности исчерпаны
Размер билда – это действительно проблема для нас. Насколько все серьезно, можно понять по некоторым дополнительным способам сжатия, которые мы изобрели.
Итого
Оптимизация размера билда – обширная тема, в этой статье описаны только общие принципы и способы сжатия ресурсов. Кроме этого обычно возникают и другие сложные вопросы:
Post scriptum
Пока статья готовилась к публикации Apple увеличила максимальный объем билда до 150 МБ. Казалось бы, стало лучше. Но в Google Play все еще остается лимит 100 МБ. В результате все получается еще сложнее. Если мы при подготовке билда для iOS будем ориентироваться только на ограничение магазина Apple в 150 МБ, то после этого при подготовке билда для Android точно не сможем уложиться в 100.
Нужно делать разные билды для iOS и Android, чтобы оптимально использовать возможности магазинов приложений. Сейчас мы все еще в процессе поиска лучшего решения. И очень ждем аналогичного шага по увеличению лимита от компании Google. После этого можно будет просто заменить в тексте статьи число 100 на 150, и в ней снова все будет правильно.
Сжимаем APK, стараясь сохранить его работоспособность
/ PxHere / PD
Оптимизация веса APK — это нетривиальная, но очень актуальная во времена Instant App, задача. Включение proguard избавит вас от ненужного кода, если ваши зависимости можно определить на этапе компиляции, но в APK есть ещё несколько видов файлов, которые можно исключить из сборки.
Под катом о том, как сделать зависимости — определяемыми на этапе компиляции, какие файлы можно исключить из сборки и как это сделать, а так же, разберём, как исключить из сборки неиспользуемые компоненты, если у вас несколько приложений с общей кодовой базой.
Перед прочтением
Лишние файлы
Начнём с простого. Если вы не используете kotlin-reflect, то можете исключить из сборки мета-информацию о kotlin-классах. Сделать это можно следующим образом:
В build.gradle (Module: app)
Зависимости
Этот код убирает зависимость библиотеки ktor-client на kotlin-reflect. Если хотите исключить что-то другое — подставьте свои значения.
Проверьте ваши XML
Проверьте ваш DI
Если вы, как и мы, используете runtime DI, то проверьте, нет ли у вас provider’ов для тех зависимостей, которые вы не используете. Proguard не может исключить их из сборки потому что они не являются неиспользуемыми с точки зрения компилятора. Вы используете их при построении графа зависимостей.
Исключите отладочные зависимости из релизной сборки
Инструменты отладки могут занимать неожиданно много места. Например, stetho весит около 0.2 мб после сжатия! В любом случае, лучше исключить из релизной сборки всю отладочную инфраструктуру, чтобы никто не смог узнать о вашем приложении слишком много, просто скачав его из Google Play.
Платформы
Иногда на одной кодовой базе выпускаются несколько разных версий приложения. Это могут быть разные версии для разных стран или регионов, или, как в нашем, случае, для разных клиентов. Ниже советы о том, как разгрузить платформу.
/ PxHere / PD
Наш опыт
Мы разрабатываем конструктор мобильных приложений E-SHOP. У нас несколько десятков клиентов и у каждого свой индивидуальный набор компонентов. Некоторые компоненты используются всеми клиентами, некоторые — только частью. Наша задача — включить в сборку клиента только те компоненты, которые ему нужны.
Исключение компонента по флагу
Это — упрощённая версия конфигурации. Настоящая сложна из-за интеграции с нашим CI.
Теперь известно, активен ли компонент, на этапе компиляции, и proguard может исключить его из сборки!
Снова XML
Теперь проблема с неиспользуемыми XML-layouts приобретает новый масштаб! Нельзя просто взять и удалить разметку какого-нибудь компонента просто потому, что некоторым клиентам он не нужен.
Аннотация @Keep
Я не нашёл простого и безопасного способа убрать эту аннотацию. Если вы знаете, как — напишите, пожалуйста, в комментариях.
И вновь DI
Последний, но не по значимости пункт. DI при отключаемых компонентах. Тут всё просто: для каждого компонента мы используем свой контейнер, а общие зависимости подключаем через отдельный модуль.
Выводы
Все оптимизации, представленные в статье — это «низковисящие фрукты». Их довольно легко внедрить и быстро получить результат. До -43% для уже оптимизированного APK в нашем случае. Надеюсь, я сэкономил ваше время тем, что перечислил всё в одном месте.
Как уменьшить размер APK файла?
Всем известно, что Android Market накладывает ограничение на размер публикуемых программ. Сегодня в магазине можно разместить приложение, размер которого не превосходит 50 Мб, но что же делать, если Вы вылезли за это ограничение?Дэвид Карлссон, архитектор приложений из Sony Ericsson, дает несколько советов, которые помогут уменьшить размер вашего apk файла.
Что такое APK формат?
APK— аббревиатура от Android application package (файл архива Android программы). Каждое Android приложение упаковывается в apk архив, содержащий исполняемый код (.dex файлы), ресурсы, активы и файл манифеста. Фактически apk представляет собой обычный zip архив, поэтому не имеет смысла предварительно сжимать файлы ресурсов каким-нибудь архиватором.
Почему нужно стремиться к экономии памяти? Размер памяти на смартфоне ограничен несколькими мегабайтами, а пользователю нужно хранить кучу разной информации: фотографии, музыку, архив сообщений. Поэтому размер приложения отнюдь не последний фактор, учитываемый пользователем при поиске программ.
Как уменьшить размер APK файла?
Ниже приводится несколько полезных советов, которые помогут вам уменьшить размер ваших Android программ.
Используйте ProGuard
ProGuard— это обфускатор, попутно сжимающий размер кода. Как известно, Java приложения компилируются в байт-код, из которого довольно просто восстановить java исходник. Для усложнения жизни любителям реверс-инженерии придумали обфускаторы. Обфускатор служит для запутывания исходного кода программы, при сохранении исходной функциональности. Получается рабочий исходник, мало пригодный для чтения человеком. Программа ProGuard помимо собственно обфускации сжимает исходный код, делает его более быстрым и менее требовательным к памяти. Очень важно после использования ProGuard провести тщательное тестирование полученного приложения. Возможны ситуации, когда в ходе оптимизации и обфускации кода изменяется его функциональность. В таких случаях важно позаботиться о сохранении symbol mapping, чтобы можно было восстановить из обфусцированного кода исходный и попытаться выявить источник проблем.
Удаляйте отладочную информацию
Дэвид рекомендует перед компиляцией финальной версии программы убрать из нее все связанные с отладкой конструкции, поскольку они не несут для пользователя ничего полезного.
Входящий в состав Android SDK компилятор умеет автоматически удалять отладочный код из релиза, но программист должен позаботиться о правильном оформлении своей программы, поместив отладочные команды в специальный блок:
Часто начинающие разработчики оформляют отладочный код в виде отдельных методов
Удаляйте отладочные символы из нативных библиотек
Использование символов отладки имеет смысл, когда ваше приложение находится в стадии разработки. Если Вы решили собрать релиз, Дэвид рекомендует удалить символы отладки из нативных библиотек (.so файлы). Это можно сделать, вызвав команду arm-eabi-strip из Android NDK.
Используйте рекомендуемые медиа форматы
Если ваше приложение содержит графику, видео и аудио данные, использование «правильных» форматов может положительно сказаться на размере приложения. Дэвид рекомендует использовать следующие форматы:
Компрессируйте PNG файлы
Довольно часто получаемые в результате работы графических редакторов PNG файлы плохо скомпрессированы и их размер может быть дополнительно уменьшен с помощью специальных утилит:OptiPNGилиPNGCrush. Обе эти программы пересжимают PNG файл, сохраняя качество картинки. Программы перебирают параметры PNG фильтров и настроек алгоритма сжатия и создают на выходе файл с оптимальными параметрами.
Используйте 9patch PNG для масштабируемых изображений
Удаляйте неиспользуемые ресурсы
Как правило, папка res содержит несколько неиспользуемых ресурсов. Для их удаления можно использовать специальную утилитуandroid-unused-resources, которая сканирует Ваш исходный код и удаляет из проекта неиспользуемые ресурсы.
Избегайте дублирования
Убедитесь, что в вашем приложении не дублируется функциональность и активы (строки, рисунки и т.п.). Важно понимать, какие Android API вы используете, и знать их функциональность. Может получиться, что в вашей программе для решения задачи, которую можно решить средствами уже подключенных API, подключается новый API. Дублирование кода, например, включение в программу функций делающих одно и то же, также ведет к разбуханию APK файлов.
Играем в APK-гольф. Уменьшение размера файлов Android APK на 99,9%
В гольфе выигрывает тот, у кого меньше очков.
Применим этот принцип в Android. Мы собираемся поиграть в APK-гольф и создать приложение минимально возможного размера, которое можно установить на Android 8.0 Oreo.
Базовый уровень
Затем установим APK на смартфон Nexus 5x под Oreo, чтобы убедиться, что всё работает.
Прекрасно. Наш APK весит примерно полтора мегабайта.
APK Analyser
Полтора мегабайта кажутся слишком большим размером с учётом того, что делает наше приложение (а оно ничего не делает), так что давайте изучим проект и поищем, где по-быстрому сэкономить на объёме. Вот что сгенерировал Android Studio:
Вопреки нашим первоначальным предположениям, похоже, что самый большой файл — Dex, а на ресурсы приходится всего 20% от размера APK.
Файл | Размер | ||||||
---|---|---|---|---|---|---|---|
classes.dex | 74% | ||||||
res | 20% | ||||||
resources.arsc | 4% | ||||||
META-INF | 2% | ||||||
AndroidManifest.xml | classes.dex — главный виновник раздутого APK, он занимает 73% всего объёма и поэтому станет первой целью оптимизации. Этот файл содержит весь наш скомпилированный код в формате Dex, а также список внешних методов во фреймворке Android и библиотеку поддержки. В пакете android.support перечисляется более 13 000 методов, что кажется излишним для приложения типа «Hello World». РесурсыВ директории res находится большое количество файлов шаблонов, чертежей (drawables) и анимаций, которые сразу не видны в интерфейсе Android Studio. Опять же, они вытянуты из библиотеки поддержки и занимают около 20% размера APK. Файл resources.arsc также содержит список всех этих ресурсов. ПодписьЗдесь нет очевидных целей для оптимизации. AndroidManifestВключаем минификациюМы ещё не пробовали включить опцию минификации и сжатия ресурсов в файле build.gradle для нашего приложения. Сделаем это. shrinkResources удалит из APK любые ресурсы, на которые нет прямой ссылки. Могут возникнуть проблемы, если вы получаете доступ к ресурсам не напрямую, но к нашему приложению это не относится. 786 КБ (уменьшение на 50%)Мы наполовину уменьшили размер APK без видимого изменения в работе программы. Если вы ещё не включили minifyEnabled и shrinkResources в своём приложении, это самая главная вещь, которую следует вынести из этой статьи. Можно легко сэкономить несколько мегабайт, потратив всего парочку часов на конфигурацию и тестирование. Прощай, AppCompat, мы едва тебя узнали108 КБ (уменьшение на 87%)Матерь божья, файл уменьшился почти в десять раз: с 786 КБ до 108 КБ. Единственным заметным изменением стало только изменение цвета тулбара, который окрасился в дефолтную тему ОС. На директорию res теперь приходится 95% размера APK из-за всех этих иконок лаунчера. Если бы эти иконки делал наш дизайнер, мы бы попытались конвертировать их в WebP, более эффективный формат, который поддерживается в API 15 и более поздних версиях. К счастью, Google уже оптимизировала наши drawables, хотя в противном случае мы бы и сами могли оптимизировать их и удалить из PNG ненужные метаданные с помощью ImageOptim. 6808 байт (уменьшение на 94%)Мы избавились почти от всех ресурсов, так что неудивительно, что размер APK уменьшился примерно на 95%. В файле resources.arsc по-прежнему упоминаются следующие ресурсы: Файл шаблона (6262 байта, сокращение на 9%)Выглядит как неплохой обмен. Имя приложения (6034 байта, сокращение на 4%)Давайте удалим strings.xml и заменим android:label в манифесте AndroidManifest буквой «A». Это кажется маленьким изменением, но удаление записи из resources.arsc уменьшает количество символов в манифесте и удаляет файл из директории res. Каждая мелочь идёт на пользу — мы только что сэкономили 228 байт. Иконка лаунчера (5300 байт, сокращение на 13%)Документация для resources.arsc в репозитории Android Platform объясняет, что каждый ресурс APK упоминается в resources.arsc с целочисленным идентификатором. У этих ID два пространства имён:
Так что произойдёт с нашим APK, если мы поставил ссылку на ресурс в пространстве имён 0x01? По идее, мы получим более красивую иконку и одновременно уменьшим размер своего файла. Само собой, вам никогда не следует доверять системным ресурсам вроде иконок в реальном рабочем приложении. Такой метод провалит валидацию в Google Play, а некоторые производители ещё и по-своему определяют белый цвет, так что действуйте осторожно. Манифест (5252 байта, сокращение на 1%)Мы ещё не трогали манифест. Удаление этих аттрибутов экономит 48 байт. Хак Proguard (4984 байта, сокращение на 5%)Похоже, что классы BuildConfig и R ещё остались в файле Dex. Уточнение правила Proguard удалит ненужные классы. Обфускация (4936 байт, сокращение на 1%)Обфусцируем имя для класса Activity. Для обычных классов Proguard автоматически делает это, но поскольку имя класса Activity вызывается через Intents, его не обфусцировали по умолчанию. META-INF (3307 байт, сокращение на 33%)В данный момент мы подписываем приложение одновременно подписями v1 и v2. Это кажется лишней тратой ресурсов, потому что v2 обеспечивает превосходную защиту и производительность, хешируя весь APK целиком. Давайте уберём галочку для подписи v1 в интерфейсе Android Studio и сгенерируем подписанный APK. Попробуем сделать и наоборот.
Похоже, теперь мы будем использовать v2. Куда мы идём — там не нужны IDEПришло время редактировать APK вручную. Используем следующие команды: Детальный обзор процесса подписи APK см. здесь. В общем, Gradle генерирует неподписанный архив, zipalign делает выравнивание по границе байта для несжатых ресурсов, чтобы оптимизировать потребление RAM после загрузки APK, и в конце запускается криптографическая процедура подписи APK. Неподписанный и невыровненный APK весит 1902 байт, то есть процедура добавляет примерно 1 килобайт. Несоответствие размеров файлов (2608 байт, сжатие на 21%)Хаки со сжатием (2599 байт, сокращение на 0,5%)Теперь изменим все оставшиеся строки на ‘c’, обновив версии до 26, а затем сгенерируем подписанный APK. Это уменьшает размер ещё на 9 байт. Хотя количество символов в файле не изменилось, но дело в том, что увеличилась частотность символа ‘c’. В результате алгоритм сжатия сработал более эффективно. Привет, ADB (2462 байт, сокращение на 5%)Можно ещё сильнее оптимизировать манифест, удалив фильтр намерения Launch для класса Activity. С этого момента будем запускать приложение следующей командой: Вот новый манифест: Мы также избавились от иконки лаунчера. Очистка от ссылок на методы (2179 байт, сокращение на 12%)По изначальным условиям, мы должны подготовить APK, который способен установиться на устройство. Исходные файлы теперь выглядят следующим образом: Используем adb для проверки, что APK успешно установился, это можно также проверить через «Настройки». Оптимизация Dex (1961 байт, сокращение на 10%)Я потратил несколько часов, изучая формат файла Dex ради этой оптимизации, поскольку разные механизмы вроде контрольных сумм и смещений затрудняют ручное редактирование. Иногда глупейшее решение — самое лучшее. Понимание манифеста (1961 байт, сокращение на 0%)Манифест неподписанного APK — это файл в бинарном формате XML, который вроде бы официально не документирован. Можно изменить содержимое файла с помощью редактора HexFiend. Непонимание манифеста (1777 байт, сокращение на 9%)А попробуем набросать случайных символов по всему файлу, а затем установить APK, не изменяя указанный размер файла. Так мы проверим, осуществляется ли проверка контрольной суммы, и как наши изменения повлияют на смещения в заголовке файла. Удивительно, но такой манифест воспринят как валидный APK на Nexus 5X под Oreo: Для максимальной выгоды нужно заменить все эти глупые символы нулевыми байтами. Это поможет распознать важные части файла в HexFiend, а также сократит несколько байт благодаря хаку сжатия, упомянутому выше. Манифест UTF-8Вот важные компоненты Manifest, без которых APK не установится. Некоторые вещи очевидны, такие как теги манифеста и пакета. В пуле строк видны versionCode и название пакета. Шестнадцатиричный манифестНо вряд ли здесь можно найти другие варианты для оптимизации. Готово? (1757 байт, сокращение 1%)Изучим окончательный APK. В течение всего этого имени в APK было указано моё имя в подписи v2. Создадим новое хранилище ключей, в котором используется хак для сжатия. Мы сэкономили 20 байт. Шаг 5: Признание1757 байт — это очень мало, чёрт возьми. И насколько я знаю, это самый маленький существующий APK. Однако я разумно полагаю, что кто-нибудь из Android-сообщества способен выполнить дальнейшие оптимизации и ещё улучшить результат. Если вы умудритесь уменьшить файл с нынешних 1757 байт, присылайте пулл-реквест в репозиторий, где хостится самый маленький APK, или сообщайте в твиттере. (С момента публикации статьи файл уже уменьшили до 820 байт — прим. пер.)
|