Pull to refresh

Unity: Сборка под Android или «размер имеет значение»

Reading time5 min
Views56K
В некоторых случаях необходимо работать над снижением размера сборки для Андроид. Например, установка тяжеловесных APK для пользователей мобильного интернета может влететь в копеечку. Превышение размера APK в 50 Мб в Google Play выливается в дополнительные трудности при аплоаде.



Мы разрабатывали под Андроид на Unity 2D-игру, которая изобилует картинками (большинство с областями прозрачности) и разнообразными звуками, и столкнулись с проблемой размера APK. Забегая вперед скажу, что решив ее и снизив вес в 1,5 раза, мы получили в 1,5 раза больше скачиваний. Заставляет задуматься, не правда ли?

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

Другую полезную информацию по данному вопросу в интернете мы практически не нашли. Потому провели небольшое исследование, результатами которого спешим с вами поделиться.

Итак, согласно документации, на размер сборки влияет:
  1. Размер ассетов (изображения и звуки);
  2. Меши и анимационные клипы;
  3. Размер включаемых dll.

С мешами и импортированными анимационными клипами мы не работали, потому начнем с ассетов.


ИЗОБРАЖЕНИЯ


Уточним насчёт изображений. В нашей игре соблюдается принцип pixel-perfect. Все изображения без альфа-канала имеют плавный градиент. Остальные изображения с прозрачностью, а непрозрачные области тоже имеют плавный градиент.

Проанализируем, какой вклад в размер АРК вносят изображения в формате PNG и JPG.

Картинки в формате PNG


Для PNG этот вклад зависит от двух «переменных»:
  1. Размер картинки на файловой системе;
  2. Настройка импорта.

Мы сохранили 3 картинки в Photoshop с настройками: Compression->Smallest/Slow, Intrelaced: No. Картинка PNG размером 295 Кбайт заняла в сборке места 236 Кбайт. Картинка 612 Кбайт заняла 480 Кбайт. Картинка 21,2 Кбайт заняла 23 Кбайт (естественно, при одинаковых настройках импорта). Пропроциональность очевидна.

Далее мы сохранили первую картинку в Photoshop с настройками: Compression->None/Fast, Intrelaced: Yes. Получили файл размером 9000 Кбайт, однако в сборку он добавил те же 236 Кбайт.

Это подтверждает слова из документации, о том, что Unity перекодирует все ассеты во внутренний формат. Очевидно, он приблизительно соответствует формату PNG, сохранённому в фотошопе с настройками: Compression->Smallest/Slow, Intrelaced: No. И Unity перекодирует все PNG в этот формат, независимо от начального формата файла.

Картинки в формате JPG


Опыты однозначно показали, что изображения JPG вносят вклад в размер сборки пропорционально своему размеру. Пока не совсем понятно, как ведёт себя Unity в случае, если ассет находится в формате JPG. Мы сохранили ту же самую (первую) картику в JPG и получили очень маленький файл на файловой системе (75 Кбайт). Однако в сборке он занял непомерных 767 Кбайт (*).

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

Еще один способ работы с JPG будет описан ниже.

Выводы
  1. Судя по всему, Unity берет во внимание и формат, в котором сохранено изображение, и характеристики изображения и выполняет сжатие по каким-либо внутренним принципам;
  2. Один принцип совершенно однозначен: изображения в одинаковом формате вносят вклад в размер сборки, прямо пропорциональный (но НЕ РАВНЫЙ) своему размеру на файловой системе.

Настройки импорта влияют на размер сборки совершенно так, как это описано в доке (чем качественнее картинка, тем больший её вклад в размер сборки). Здесь скрытых особенностей не выявлено. (С другими форматами изображений эксперименты пока не проводились.)

ЗВУКИ


Для звуков значение имеют две настройки импорта: Audio Format и ForceToMono.

Файлы в формате WAV занимают больше места в сборке, чем файлы в формате MP3 (вклад в размер сборки приблизительно равен размеру файла). Стерео WAV файл займёт меньше места, если выставить ForceToMono = true. Точно такого же эффекта можно достичь, если конвертировать файл в «моно» ещё до импорта (тогда ForceToMono не будет доступна в инспекторе).

Однако если для файла WAV установить настройку импорта AudioFormat = Compressed, то в сборке он займёт места столько же, сколько и соответствующий MP3 файл высшего качества (Audacity: variable bitrate, 220-260 kbps). То есть Unity самостоятельно кодирует звук в формат MP3.

Для файлов в одинаковом формате действует принцип прямо пропорционального вклада в размер сборки.

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

А ТЕПЕРЬ О КОНКРЕТНЫХ ШАГАХ К НАШЕЙ ЦЕЛИ


  1. По возможности снижать размер и качество исходных файлов графики.
    (1-a) Обрезка областей прозрачности.
    В нашей игре использовалось много картинок с внушительными областями прозрачности вокруг изображения. Области прозрачности лишь на считанные проценты увеличивают размер файла и не очень влияют на размер сборки (хотя обрезка 102х немаленьких картинок сэкономила нам 2 Мбайт). Но области прозрачности увеличивают использование RAM (поскольку там картинки представляются в BMP).

    Таким образом, совет: для снижения нагрузки на ОЗУ
    * избегать больших областей прозрачности в изображениях;
    * не формировать атласы с большими участками прозрачности, особенно в NGUI.

    (Но это мы отвлеклись от основной темы.)

  2. Изображениям, не имеющим прозрачности и отображаемым в самом высоком качестве, в настройках импорта необходимо задать Advanced->RGB24. RGBA32 для них не имеет смысла, а вот оставлять Automatic Truecolor не рекомендуется, потому что (как показал опыт) он может восприняться системой как RGBA32. А это является совершенно лишним при отсутствии областей прозрачности (добавляет веса сборке и увеличивает использование RAM).
  3. Снизить качество изображений в настройках импорта по схеме: 32 bit -> 24 bit -> 16 bit, наблюдая за тем, чтобы уровень качества изображения оставался в пределах допустимого.
  4. Ограничить maxTextureSize для изображений, для которых это возможно с сохранением приемлемого качества.
  5. Тщательно вручную удалять неиспользуемые ассеты в папках Resources перед процессом сборки. Помните, что для ассетов, лежащих в папках Resources, Unity НЕ производит автоматическое их удаление, даже если они не назначены в Инспекторе.
  6. Для изображений JPG: сменить расширение файла на bytes и он превратится в TextAsset. После чего воспользоваться функцией Texture2D.LoadImage() для загрузки картинки. Следует помнить, что эта функция нагружает процессор и может оказаться неподходящей в случае больших картинок, которые необходимо очень быстро загрузить. Однако этот способ зачастую помогает внушительно облегчить сборку.
  7. Уменьшить размер звуковых файлов до минимально возможного размера (с учётом требований к качеству). По возможности использовать MP3, а не WAV. Но если нужны MP3 самого высокого качества, можно пользовать и WAV-файл с настройкой импорта AudioFormat = Compressed (Unity перекодирует самостоятельно). По возможности использовать Mono вместо Stereo. Для WAV-файлов — выставлять настройку импорта ForceToMono = true

После выполнения каждого пункта желательно проверять полученный эффект. Поскольку в поведении Unity всё же есть доля магии.

Несколько слов о dll


Документ приводит список обязательно включаемых в сборку dll и призывает минимизировать количество дополнительных dll (особенно тяжёлых). В частности, по возможности не использовать System.dll (добавляет к APK 2 Мбайт). Однако даже если мы будем избегать ссылок на методы из этой библиотеки, System.dll всё равно (по состоянию на Unity 4.5.5) включается в сборку, так как её подтягивает обязательная Mono.Security.dll. Потому, получается, что официальная документация Unity в этом месте не совсем релевантна.

А вот использования других (необязательных) dll желательно избегать во имя снижения размера сборки.

На сегодня у нас всё. Спасибо за внимание!

(Просьба рассматривать данный материал как более-менее систематизированные результаты исследования, а не как универсальное руководство к действию. Буду очень рад комментариям, замечаниям, конструктивной критике, возражениям, предложениям, дополнениям. И, конечно, несказанно рад буду узнать, какие приёмы применяют коллеги из других компаний для решения обсуждаемого вопроса.)
Tags:
Hubs:
+13
Comments40

Articles

Change theme settings