В Xamarin.Android приложение собирается в один APK‑файл, который содержит как управляемый код (.NET‑сборки), так и нативные библиотеки (libmono, libandroid‑runtime, сторонние .so‑файлы). Одним из главных факторов, определяющих итоговый размер APK, является набор поддерживаемых ABI (Application Binary Interface) – архитектур процессора, для которых включены нативные библиотеки.
В этой статье мы разберём:
- Что такое ABI и какие варианты поддерживает Xamarin.Android;
- Как включение нескольких ABI влияет на размер APK;
- Методы уменьшения размера пакета без потери совместимости;
- Практические примеры конфигурации проекта (csproj, Gradle‑подобные параметры);
- Инструменты анализа и отладки размеров 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, ваш помощник по мобильной разработке.