Build
03.04.2024 | https://habr.com/ru/companies/cian/articles/804835/ |
01.10.2020 | https://habr.com/ru/articles/521522/ |
https://docs.gradle.org/current/userguide/compatibility.html |
https://docs.gradle.org/current/userguide/build_environment.html |
R8
Используется вместо Proguard начиная с версии AGP 3.4.
NDK
Native Development Kit – набор инструментов, которые помогают работать с кодом, написанным на языках C и C++. NDK предоставляет API для доступа к физическим компонентам девайса, таким как сенсоры. Кроме того NDK позволяет скомпилировать и включить в APK C/C++ код, используя Gradle. NDK часто используется в геймдеве для увеличения производительности и для ручного управления памятью. Для взаимодействия нативного и Java-кода используется собственный интерфейс Java - JNI, он определяет способ взаимодействия байт-кода, который Android компилирует из управляемого кода (написанного на языках программирования Java или Kotlin), с собственным кодом (написанным на C/C++).
JNI
Java Native Interface. Стандартный механизм для запуска кода под управлением JVM, который написан на языках C/C++ или Ассемблере и скомпонован в виде динамических библиотек; позволяет не использовать статическое связывание. Это даёт возможность вызова функции C/C++ из программы на Java, и наоборот.
Android
ОС для смартфонов, планшетов, носимой электроники и бытовых устройств с открытым исходным кодом. Основана на ядре Linux. Android использует собственную реализацию виртуальной машины Java - ART. Позволяет запускать Java-приложения, управляющие устройством через разработанные Google библиотеки.
ART
Android Runtime (ART) - среда выполнения приложений Android, замена Dalvik, преобразовывает байт-код приложений в собственные инструкции, которые выполняются на устройстве.
jar
Java Archive. Содержит классы Java, может использоваться как в Android-приложениях, так и в чистой Java.
aar
Android Archive. Аналогичен модулю приложения Android. Может включать исходный код (классы и методы Java), файлы ресурсов, манифест. Может содержать библиотеки C/C++.
Debugger
• устанавливать точки останова (поэтапное выполнение программ)
• проверять значения переменных
Запустить отладку
• Run → Attach Debugger to Android Process (или иконка жука со стрелкой)
• Нажать иконку жука
• Открыть окно Debug
Breakpoints
Точки останова. Позволяют приостанавливать выполнение приложения на нужной строчке кода, проверять значения переменных и продолжать выполнение кода строчка за строчкой.
Incremental build
Запуск компилятора в рамках одного модуля только на тех файлах, которые изменились, либо имеют прямую зависимость от измененных файлов.
Modularization
Есть несколько причин для многомодульности: время сборки, возможность повторного переиспользования кода, техническое обслуживание и разделение ответственности, легкое тестирование автономных функций, демонстрационные приложения, запустить одну изолированную функцию вместо запуска всего проекта после небольшого изменения.
Gradle
Система автоматической сборки проектов.
miSdk
Минимальная версия Android, на которой ваше приложение может работать. Определяет, какие API и функции из SDK доступны при компиляции. Это не влияет на то, на каких версиях Android ваше приложение будет работать, а лишь на то, какие функции и классы вы можете использовать в коде.
compileSdk
Версия Android SDK, которую вы используете для компиляции вашего приложения.
targetSdk
Версия Android, с которой ваше приложение была протестировано и оптимизировано. Это указывает системе Android, что ваше приложение знает о новых функциях и изменениях в поведении, добавленных в этой версии. Помогает Android системе правильно управлять поведением вашего приложения при изменении версий Android. Например, если есть изменения в политике безопасности или разрешениях, ваше приложение будет вести себя так, как если бы оно было запущено на устройстве с этой версией Android.
Подключение модулей и зависимостей
Конфигурация | Поведение |
---|---|
implementation | Получить доступ к модулю или библиотеке без внутренних зависимостей. Использование улучшает время сборки. |
api | Замена устаревшего compile . Получить доступ к модулю или библиотеке. А также к модулям и библиотекам подключенным внутри. Позволяет транзитивно использовать внутренние зависимости в compiletime и runtime. |
compileOnly | Зависимость доступна только в compiletime. Например библиотека только с аннотациями для генерации кода. Нельзя использовать с AAR. |
runtimeOnly | Зависимость доступна только в runtime. Редко используется. Пример - логирование в серверных приложениях. |
kapt | Замена устаревшего annotationProcessor . Обработчики аннотаций поддерживаются с помощью плагина кампилятора kapt (замена annotationProcessor). Kapt использует компилятор Java для запуска обработчиков аннотаций. |
ksp | Kotlin Symbol Processing - используется для легковесных подключаемых модулей. Работает до 2 раз быстрее kapt. Не привязан к JVM. Минимизирует время сборки. |
Build Variants & Product Flavors
Настраиваемые варианты сборки, для создания разных версий приложения из одного проекта. Gradle использует определенный набор правил для объединения настроек, кода и ресурсов, настроенных в ваших типах сборки и вариантах продукта.
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
signingConfig = signingConfigs.getByName("release")
applicationIdSuffix = MoviesBuildType.RELEASE.applicationIdSuffix
manifestPlaceholders += mapOf("appName" to "@string/app_name")
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
debug {
isDebuggable = true
isMinifyEnabled = false
isShrinkResources = false
applicationIdSuffix = MoviesBuildType.DEBUG.applicationIdSuffix
manifestPlaceholders += mapOf("appName" to "@string/app_name_dev")
isDefault = true
}
}
flavorDimensions += "version"
productFlavors {
create("gms") {
dimension = "version"
applicationId = "org.michaelbel.moviemade"
isDefault = true
}
create("hms") {
dimension = "version"
applicationId = "org.michaelbel.movies"
}
create("foss") {
dimension = "version"
applicationId = "org.michaelbel.movies"
}
}
ProGuard
Инструмент оптимизации и обфускации (запутывание) Java кода. Proguard удаляет неиспользуемые классы и методы из уже скомпилированного приложения. Это позволяло решать проблему 64К методов до появления MultiDex. Java- и Dalvik-байткод легко декомпилировать. Для серверного Java-приложения это не проблема, а вот к байткоду приложения под Android доступ имеет любой пользователь. Proguard обфусцирует код, что усложняет задачу декомпиляции. Этот инструмент обрабатывает уже скомпилированный Java код, так что он должен работать с любым JVM языком. Сам язык для Proguard безразличен, важен только байткод. Все манипуляции Proguard с байткодом можно разделить на 3 основных категории: Code shrinking, Optimisation и Obfuscation.
Работает в Release
- не работает в Debug
?
Проблема в Proguard
@Keep
Гарантирует, что аннотированный класс или метод не будет удален при минимизации кода во время сборки. Обычно добавляется к методам и классам, доступ к которым осуществляется через рефлексию, чтобы компилятор не рассматривал код как неиспользуемый. Классы и методы @Keep всегда появляются в APK-файле, даже если вы никогда не ссылаетесь на эти классы и методы в логике приложения.
APK (Android Package)
Формат пакета для приложений на платформе Android. Он содержит все необходимые файлы и ресурсы, которые требуются для установки и запуска приложения на устройстве Android. APK-файл представляет собой архив, который можно рассматривать как “упакованный” контейнер для всего, что нужно для работы приложения.
Компоненты APK-файла
• META-INF
Содержит метаданные о приложении, включая цифровые подписи и сертификаты, которые используются для проверки целостности и подлинности APK.
• MANIFEST.MF
Файл манифеста, который содержит общую информацию о содержимом архива, например, метаданные подписи.
• CERT.RSA
Цифровая подпись для проверки целостности файла.
• CERT.SF
Файл, который содержит список файлов в APK и их хэши для проверки целостности.
• res
Содержит ресурсы приложения, такие как файлы разметки (XML), изображения и другие ресурсы, которые не являются кодом. Эти файлы упакованы в формат, оптимизированный для быстрого доступа.
• assets
Содержит произвольные файлы и папки, которые приложение может использовать в процессе выполнения. В отличие от ресурсов в папке res, файлы в папке assets не обрабатываются системой Android и могут быть любого формата.
• lib
Содержит скомпилированные библиотеки и файлы .so (shared objects) для различных архитектур процессора (например, ARM, x86). Эти библиотеки могут использоваться приложением для выполнения задач на низком уровне или взаимодействия с платформенными функциями.
• classes.dex
Содержит скомпилированные байт-коды Java (в формате Dalvik Executable) или Kotlin, которые выполняются виртуальной машиной Android (ART/Dalvik). Это основной исполняемый код приложения.
• AndroidManifest.xml
Основной файл конфигурации, который описывает компоненты приложения (активности, службы, приемники, провайдеры контента) и задает разрешения, необходимые приложению. Этот файл также содержит информацию о версии приложения и других свойствах.
• resources.arsc
Содержит предварительно скомпилированные ресурсы (например, строки, стили, размеры) в бинарном формате, который позволяет быстро извлекать их во время выполнения приложения.
Структура APK-файла
MyApp.apk
├── AndroidManifest.xml
├── classes.dex
├── res/
│ ├── drawable/
│ ├── layout/
│ ├── mipmap/
│ └── values/
├── assets/
│ └── some_file.txt
├── lib/
│ ├── armeabi/
│ └── x86/
└── META-INF/
├── CERT.RSA
├── CERT.SF
└── MANIFEST.MF
Как уменьшить APK?
• Оптимизация ресурсов. Удалите ненужные ресурсы, используйте форматы изображений с меньшим размером (WebP), не включаете ресурсы для всех разрешений экранов, если они не нужны.
• Использование ProGuard и R8. Удалите неиспользуемый код и оптимизируйте его. Обфусцируй и сожми код.
• Разделение APK на модули. Создать разные APK для различных архитектур процессоров или разрешений экрана.
• Оптимизация библиотек. Удалите лишние зависимости.
• Упрощение кода. Не оставляете неиспользуемый код в проекте.
• Сжатие файлов. Используйте инструменты для сжатия ресурсов и файлов, такие как pngcrush или jpegoptim для изображений.
• Использование shrinkResources. Этот флаг удаляет неиспользуемые ресурсы из APK.
• Использование Android App Bundle. Позволяет Google Play автоматически генерировать APK для различных конфигураций устройств. Это помогает сократить размер скачиваемого APK для конечного пользователя.
Как взломать APK?
• Распаковать APK. Сразу можно посмотреть AndroidManifest (exported=true). Запустить компоненты. Узнать установлено ли приложение на телефон.
• Просмотреть strings.xml. Там могут лежать ключи.
• Украсть сертификат SSL Pinning из папки raw.
• Перевести .dex в .jar утилитой dex2jar.
• Найти методы Retrofit и получить доступ к коду всех методов работы с сервером.
• Включить debug-меню если разработчики не удаляют его код из release-версии.
.dex
DEX файл – результат компиляции кода Android-приложения. Расшифровывается как Dalvik Executable, но несмотря на это используется и на устройствах со средой исполнения ART. В Java-программах каждый .java файл компилируется в отдельный .class файл. DEX аналогичен файлам .class, но содержит байткод всего приложения (или части приложения в случае Multidex), а не одного класса.
Проблема 64k методов
Это ограничение на количество методов в одном .dex-файле. Максимальное количество методов в .dex-файле равно 65536. На ранних версиях Андроида приложение могло иметь только один .dex-файл. Проблема 64К ограничивала количество методов в приложении. Один класс в Java может иметь максимум 64К методов. В Андроиде .dex-файл сделан по образу .class и поэтому наследует это ограничение. Причина ограничения в том, что под индексы ссылок на методы в java- и dalvik-байткоде выделено 16 бит. Т.е. максимальное число 2^16 = 65536. На ранних версиях Андроида единственным решением было уменьшение количества методов. Для этого использовался Proguard. Сейчас проблема решается включением Multidex. В этом случае приложение может иметь более одного .dex-файла.
AAB (Android App Bundle)
AAB - файловый формат публикации приложений для Android. AAB содержит код и ресурсы, необходимые для конфигурации конкретного устройства. Если пользователь изменит язык устройства или набор функций, магазин приложений может запросить дополнительные разделенные APK для удовлетворения изменившихся требований.
Zygote
Ключевой процесс, который служит для создания новых процессов приложений. Он работает как предзагруженный процесс, из которого создаются копии для каждого приложения с помощью механизма форка (forking). Это позволяет значительно ускорить запуск приложений и сэкономить память.
• Инициализация. При загрузке системы Zygote запускается и загружает все необходимые библиотеки, компоненты и классы, общие для всех приложений Android.
• Fork (разветвление). Когда нужно запустить новое приложение, Zygote делает “fork” — создаёт новый процесс, который является копией самого процесса Zygote. Это копирование позволяет новому процессу использовать уже загруженные системные ресурсы.
• Оптимизация. За счёт предзагрузки общих ресурсов и быстрого разветвления процесс Zygote существенно ускоряет запуск приложений и снижает использование оперативной памяти, так как часть данных (например, классы и библиотеки) остаётся общей для всех приложений.
Приоритеты процессов
- Foreground Process (Процесс переднего плана): Наивысший приоритет. Содержит активные пользовательские приложения и процессы, которые напрямую взаимодействуют с пользователем. Всегда остается в памяти и не подвержен убийству системой при нехватке ресурсов.
- Visible Process (Процесс видимого приложения): Высокий приоритет. Содержит процессы приложений, которые видимы пользователю, но не активны. Может быть убит системой, если ей нужно освободить память, но только после более низко приоритетных процессов.
- Service Process (Процесс службы): Средний приоритет. Содержит процессы, которые выполняют фоновую работу (например, службы, выполняющие долгие задачи). Убиваются только в последнюю очередь, если система нуждается в освобождении ресурсов.
- Background Process (Процесс фонового приложения): Низкий приоритет. Содержит приложения, которые не видны пользователю и не выполняют активные задачи. Могут быть убиты системой в первую очередь при нехватке памяти.
- Empty Process (Пустой процесс): Наименьший приоритет. Содержит процессы, которые больше не используются и освободили всю память. Убиваются первой, когда системе нужно освободить ресурсы.
CI/CD
Непрерывная интеграция (Continuous Integration, CI) и непрерывная поставка (Continuous Delivery, CD) представляют собой культуру, набор принципов и практик, которые позволяют разработчикам чаще и надежнее развертывать изменения программного обеспечения. Цель CI — обеспечить последовательный и автоматизированный способ сборки, упаковки и тестирования приложений. Непрерывная поставка начинается там, где заканчивается непрерывная интеграция. Она автоматизирует развертывание приложений в различные окружения.
Doze Mode
Функция управления энергопотреблением в Android, предназначенная для увеличения времени работы устройства от батареи. Была впервые представлена в Android 6.0 и значительно улучшает управление энергией, снижая потребление батареи для приложений, которые не находятся в активном использовании.
• Активирование. Doze Mode активируется, когда устройство находится в состоянии покоя. Это происходит, когда экран выключен, и устройство не перемещается в течение определенного времени.
• Режимы работы. Когда устройство находится в покое в течение более длительного времени, Doze Mode переходит в более строгий режим экономии энергии, при котором доступ к сети и частичным пробуждениям ограничен еще больше.
• Ограничение фоновых операций. Doze Mode ограничивает фоновые операции, такие как синхронизация данных и сетевые запросы, чтобы снизить энергопотребление.
• Ограничение активности. Приложения не могут выполнять фоновую работу или получать сообщения до тех пор, пока не произойдут запланированные интервалы пробуждения (standby maintenance windows).
• Смарт-уведомления. Приложения могут обрабатывать уведомления в рамках ограничений Doze Mode, но время их доставки может быть отложено до следующего пробуждения устройства.
• Пробуждение устройства. Doze Mode не влияет на высоко приоритетные события, такие как входящие вызовы и сообщения, которые могут пробудить устройство. Также может быть пробуждено с помощью действий пользователя, таких как нажатие кнопок или взаимодействие с экраном.
• Настройки и исключения. Пользователи могут управлять некоторыми аспектами Doze Mode через настройки устройства, но основное поведение управляется системой. Приложения могут запрашивать исключения от Doze Mode через механизм “whitelist”, если они требуют постоянного фона для критичных задач (например, для приложений для отслеживания местоположения или уведомлений о сообщениях).
• Старые устройства. На устройствах, работающих под управлением Android 5.1 или ниже, аналогичные функции экономии энергии называются “App Standby” и имеют более ограниченные возможности по сравнению с Doze Mode.
• Если ваше приложение не выполняет критически важные задачи в фоновом режиме, оно может быть приостановлено в Doze Mode, и система выполнит фоновые операции (такие как синхронизацию данных) только в рамках определенных интервалов. Это помогает сохранить заряд батареи и улучшить общую производительность устройства.
AIDL
Android Interface Definition Language. Язык межпроцессного взаимодействия. Разные процессы не имеют общего пространства памяти, поэтому данные между процессами передаются через сообщения. Интерфейс передачи данных создается на языке AIDL. AIDL поддерживает передачу объектов Parcelable
и Serializable
.
ANR
Application Not Responding – системный диалог для пользователя, когда приложение зависает. Отображается если: не поступает ответа от UI (нажатие на экран) за 5 сек, broadcastReceiver не завершил выполнение за 10 сек. Частая причина ANR – IO-операции в главном потоке (чтение/запись в бд).
Android Build. Вопросы на собесе
- Для чего нужен ProGuard?
- Что такое проблема 64k методов?
- Разница между implementation и api?
- Как уменьшить APK?
- Что такое Doze Mode?
- Различие между compileSdk и targetSdk?
- Уменьшилась скорость сборки проекта, в чем может быть проблема?
- Что происходит когда пользователь нажимает на иконку приложения и до вызова Application.onCreate?
Когда пользователь нажимает на иконку приложения, система создает новый процесс через форк процесса Zygote, загружает ресурсы и компоненты приложения, создает объект
Application
, а затем вызывает методApplication.onCreate()
.
- Как ускорить холодный старт приложения?
Отложить инициализацию тяжелых ресурсов в Application.onCreate, делать инициализацию ленивой, использовать библиотеку AppStartup, оптимизовать код с помощью ProGuard и R8.
- В чем преимущества многомодульности?
Многомодульность в Android улучшает структуру проекта, ускоряет сборку, облегчает повторное использование кода и тестирование, а также упрощает управление зависимостями и параллельную разработку.
- Что такое ANR?
• App nothing to request
• Application not responding
• Application nobody request
• Android not responding