Оптимизация размера APK в Xamarin.Android: работа с ABI

Узнайте, как выбор правильных ABI кардинально сокращает вес вашего Xamarin.Android приложения. Собираем легкий APK без потерь производительности!

Бесплатная консультация юриста

+7 (800) 301-07-30

Реклама jurik.ru

В Xamarin.Android приложение собирается в один APK‑файл, который содержит как управляемый код (.NET‑сборки), так и нативные библиотеки (libmono, libandroid‑runtime, сторонние .so‑файлы). Одним из главных факторов, определяющих итоговый размер APK, является набор поддерживаемых ABI (Application Binary Interface) – архитектур процессора, для которых включены нативные библиотеки.

В этой статье мы разберём:

  1. Что такое ABI и какие варианты поддерживает Xamarin.Android;
  2. Как включение нескольких ABI влияет на размер APK;
  3. Методы уменьшения размера пакета без потери совместимости;
  4. Практические примеры конфигурации проекта (csproj, Gradle‑подобные параметры);
  5. Инструменты анализа и отладки размеров APK.

Что такое ABI и какие варианты поддерживает Xamarin;Android

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

  • armeabi‑v7a – 32‑разрядные ARM‑процессоры (основная часть старых устройств).
  • arm64‑v8a – 64‑разрядные ARM‑процессоры (современные смартфоны).
  • x86 – 32‑разрядные Intel‑процессоры (редко, но встречаются в эмуляторах).
  • x86_64 – 64‑разрядные Intel‑процессоры (эмуляторы, некоторые планшеты).

В Xamarin.Android каждый ABI имеет свою папку lib/<abi>/ внутри APK, где находятся нативные библиотеки, такие как libmonodroid.so, libaot-*.so и любые сторонние .so‑файлы.

Почему Xamarin.Android использует несколько ABI?

По умолчанию Xamarin.Android собирает универсальный APK, включающий все поддерживаемые ABI. Это гарантирует, что приложение запустится на любой устройстве, но приводит к значительному росту размера пакета (обычно от 5 МБ до 30 МБ только из‑за нативных библиотек).


Как включение нескольких ABI влияет на размер APK

Ниже представлена типичная оценка размеров нативных библиотек в Xamarin.Android (данные получены на примере проекта с включённым LinkMode=SdkOnly и без AOT):

ABI Размер lib/ (KB) Примерные файлы
armeabi‑v7a ≈ 6 500 libmonodroid.so, libaot-MyApp.dll.so, libsqlite3.so
arm64‑v8a ≈ 8 200 libmonodroid.so, libaot-MyApp.dll.so, libsqlite3.so
x86 ≈ 6 800 libmonodroid.so, libaot-MyApp.dll.so
x86_64 ≈ 8 400 libmonodroid.so, libaot-MyApp.dll.so

Если собрать APK со всеми четырьмя ABI, суммарный размер нативных библиотек превысит 30 МБ. При этом управляемый код (.NET‑сборки) обычно добавляет ещё ~5‑10 МБ.


Способы уменьшения размера APK без потери совместимости

Split APK (многопакетный выпуск)

Самый простой способ – генерировать отдельные APK для каждой ABI. Google Play поддерживает split APK (или Android App Bundle (AAB)), который автоматически доставляет пользователю только нужный набор библиотек.

В Xamarin.Android включить split‑пакетирование можно через свойства проекта:

<PropertyGroup>
 <AndroidSupportedAbis>armeabi-v7a;arm64-v8a;x86;x86_64</AndroidSupportedAbis>
 <AndroidPackageFormat>aab</AndroidPackageFormat> <!-- или apk, но с SplitApk=true -->
 <AndroidSplitApk>True</AndroidSplitApk>
</PropertyGroup>

При публикации в Google Play будет создан один .aab файл, а сервис автоматически генерирует нужные .apk‑пакеты (по одному для каждой ABI). Пользователь получает минимальный размер.

Выбор только нужных ABI

Если ваша целевая аудитория использует только 64‑разрядные устройства, можно исключить 32‑разрядные ABI:

<PropertyGroup>
 <AndroidSupportedAbis>arm64-v8a;x86_64</AndroidSupportedAbis>
</PropertyGroup>

Это уменьшит размер примерно на 12‑15 МБ, но приложение перестанет работать на старых 32‑разрядных устройствах.

Удаление неиспользуемых нативных библиотек

  • Linker – включите LinkMode=Full (или SdkOnly + LinkerPleaseInclude) для удаления неиспользуемого кода из сборок.
  • Strip native libraries – в csproj добавьте:
    <AndroidStripNativeLibraries>True</AndroidStripNativeLibraries>

    Это удалит отладочные символы из .so‑файлов;

  • Удаление AOT‑библиотек – если вы не используете AOT (Ahead‑of‑Time), отключите её:
    <AndroidEnableAot>False</AndroidEnableAot>

    AOT генерирует отдельный .so‑файл для каждой сборки, что сильно увеличивает размер.

Использование android:extractNativeLibs="false"

По умолчанию нативные библиотеки извлекаются в файловую систему при установке, что требует их дублирования в виде отдельного apk‑раздела. Установив атрибут android:extractNativeLibs="false", библиотеки будут загружаться напрямую из APK, экономя до 2 МБ.

<PropertyGroup>
 <AndroidExtractNativeLibs>False</AndroidExtractNativeLibs>
</PropertyGroup>

Сжатие ресурсов и использование ProGuard/R8

Хотя это не относится напрямую к ABI, уменьшение размеров ресурсов (изображений, шрифтов) и запуск R8 (замена ProGuard) дополнительно сокращает общий размер APK.


Практический пример конфигурации проекта

Ниже – полностью готовый .csproj‑файл с оптимизированными настройками для выпуска:

<Project Sdk="Microsoft.NET.Sdk">
 <PropertyGroup>
 <TargetFramework>xamarinandroid11.0</TargetFramework>
 <OutputType>Exe</OutputType>
 <RootNamespace>MyApp</RootNamespace>
 <!-- Выбираем только 64‑разрядные ABI -->
 <AndroidSupportedAbis>arm64-v8a;x86_64</AndroidSupportedAbis>

 <!-- Публикуем в формате AAB (Google Play) -->
 <AndroidPackageFormat>aab</AndroidPackageFormat>

 <!-- Отключаем AOT, чтобы избавиться от лишних .so -->
 <AndroidEnableAot>False</AndroidEnableAot>

 <!-- Убираем отладочные символы из нативных библиотек -->
 <AndroidStripNativeLibraries>True</AndroidStripNativeLibraries>

 <!-- Не извлекать нативные библиотеки при установке -->
 <AndroidExtractNativeLibs>False</AndroidExtractNativeLibs>

 <!-- Полный линкер для уменьшения управляемого кода -->
 <AndroidLinkMode>Full</AndroidLinkMode>

 <!-- Включаем R8 (по умолчанию в Xamarin.Android 13+) -->
 <AndroidEnableR8>True</AndroidEnableR8>
 </PropertyGroup>

 <ItemGroup>
 <PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
 <PackageReference Include="Xamarin.Forms" Version="5.0.0.2244" />
 </ItemGroup>
</Project>

С такой конфигурацией типичный размер .aab для простого приложения составляет около 12‑15 МБ, а отдельный .apk для arm64-v8a – около 8 МБ.


Инструменты анализа размера APK

  • Android Studio → Build → Analyze APK – позволяет увидеть, какие файлы занимают место, в т.ч. распределение по ABI.
  • apktool – распаковывает APK и показывает содержимое папки lib/.
  • adb shell pm list packages -f – выводит путь к установленному APK, после чего можно сравнить размеры на устройстве.
  • dotnet publish -c Release -f net7.0-android /p:AndroidPackageFormat=aab – выводит размер итогового AAB в консоли.

Пример вывода Analyze APK:

Size (KB) Path
---------- ---------------------------------
 8 200 lib/arm64-v8a/libmonodroid.so
 8 200 lib/arm64-v8a/libaot-MyApp.dll.so
 5 300 lib/armeabi-v7a/libmonodroid.so
 5 300 lib/armeabi-v7a/libaot-MyApp.dll.so
 2 500 assets/Resources/Images/logo.png
 1 200 assemblies/MyApp.dll
 ...

С помощью этих инструментов можно быстро определить, какие ABI «тяжелят» ваш пакет, и принять решение о их исключении или о переходе на AAB.


Часто задаваемые вопросы (FAQ)

Можно ли собрать один APK только для 64‑разрядных устройств и при этом поддерживать 32‑разрядные?

Нет. 32‑разрядные устройства требуют 32‑разрядных нативных библиотек. Если вы хотите поддержать их, необходимо включить armeabi-v7a (и, при необходимости, x86).

Стоит ли использовать AOT в продакшн‑версии?

AOT улучшает стартовое время и уменьшает JIT‑нагрузку, но добавляет отдельный .so‑файл для каждой сборки, что увеличивает размер на 5‑10 МБ. Для большинства приложений, где размер критичен, рекомендуется отключать AOT и полагаться на JIT + Full Linker.

Как проверить, какие ABI действительно загружаются на устройстве?

Запустите приложение и выполните в логкате:

adb logcat | grep "libmonodroid.so"

В логе будет указано, из какой папки /data/app/.../lib/<abi>/ загружена библиотека.

Можно ли комбинировать split APK и AAB?

Да. Если вы публикуете AAB, Google Play автоматически создаёт split‑APK для каждой ABI. Если же вы распространяете APK вручную, включите AndroidSplitApk=True в .csproj – будет создано несколько APK‑файлов.


Множественный набор ABI в Xamarin.Android напрямую влияет на размер APK, добавляя по 5‑8 МБ за каждую архитектуру. Чтобы минимизировать размер без потери совместимости, рекомендуется:

  • Публиковать приложение в формате Android App Bundle (AAB) – Google Play будет доставлять только нужные ABI.
  • Если используете обычный APK, включайте split APK и отключайте ненужные ABI.
  • Отключайте AOT, если он не нужен, и включайте полное линкование и стрипинг нативных библиотек.
  • Устанавливайте android:extractNativeLibs="false" для экономии места при установке.
  • Регулярно анализируйте размер пакета с помощью Analyze APK и apktool.

Соблюдая эти рекомендации, вы сможете сократить размер вашего Xamarin.Android‑приложения до 10‑12 МБ (для базовых функций) и обеспечить быстрый загрузочный процесс даже на медленных сетях.


Автор: ChatGPT, ваш помощник по мобильной разработке.