- Объяснять разницу между
versionCodeиversionNameи настраивать релизную сборку - Создавать подписанный App Bundle и понимать роль Play App Signing
- Проходить тестовые треки в Play Console и публиковать приложение
- Писать модульные и UI-тесты и применять правила доступности и производительности
Приложение готово: экраны, навигация, сеть, база данных. Пора доставить его на телефоны друзей и тысяч пользователей. Путь состоит из нескольких шагов: задать версию, подписать, подготовить страницу приложения в Google Play Console, проверить с тестировщиками и наконец опубликовать. По дороге займёмся и качеством: тестами, доступностью и скоростью.
Версия и релизная сборка
У Android-приложения два номера версии. **versionCode — целое число, которое видят только система и Google Play; у каждой новой загрузки он должен быть больше прежнего. versionName** — строка, которую пользователи видят в магазине, например 0.1.0. Часто используют семантическое версионирование: MAJOR.MINOR.PATCH — крупное изменение, новая функция, исправление ошибки.
android {
defaultConfig {
applicationId = "com.educora.app"
minSdk = 24
targetSdk = 36
versionCode = 102
versionName = "0.1.2"
}
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}isMinifyEnabled включает R8: неиспользуемый код удаляется, остальной сжимается и оптимизируется; isShrinkResources убирает ненужные ресурсы.Подпись и App Bundle
Android устанавливает только подписанные приложения: подпись подтверждает автора и то, что обновление пришло из того же источника. Новые приложения загружают в Google Play в формате Android App Bundle (.aab). Ты подписываешь бандл своим ключом загрузки (upload key), а через Play App Signing Google подписывает APK для пользователей ключом подписи приложения, который хранит у себя. Из бандла каждое устройство получает только нужные ему части, поэтому загрузка меньше.
- 1Открой меню
Выбери
Build › Generate Signed Bundle / APK, отметьAndroid App Bundleи нажмиNext. - 2Создай хранилище ключей
Нажми
Create new…и укажи расположение файла.jks, пароли, имя ключа (alias) и данные владельца. Срок действия выбери не меньше 25 лет. - 3Выбери вариант release
В следующем окне выбери вариант
releaseи нажмиCreate. Готовый файл.aabпоявится в папкеapp/release.
Google Play Console
Для публикации нужен аккаунт разработчика Google Play: разовый регистрационный взнос 25 долларов США и подтверждение личности. Затем в Play Console нажимают Create app и заполняют несколько разделов: страницу в магазине (название до 30 символов, краткое описание до 80, полное до 4000, значок 512×512, главная картинка 1024×500, скриншоты), содержание приложения (политика конфиденциальности, форма Data safety, анкета возрастного рейтинга, целевая аудитория) и выпуск.
| Трек | Кто видит |
|---|---|
| Внутреннее тестирование | до 100 выбранных тестировщиков; новые версии приходят быстро |
| Закрытое тестирование | приглашённые списки адресов или группы |
| Открытое тестирование | любой, кто присоединится со страницы в Google Play |
| Рабочая версия (production) | все пользователи |
Тесты
Модульные тесты лежат в папке src/test и выполняются на компьютере, без телефона, за секунды — идеально для проверки логики (вычислений, ViewModel). Инструментальные тесты лежат в src/androidTest и выполняются в эмуляторе или на телефоне; ими проверяют экраны Compose.
fun percent(correct: Int, total: Int): Int =
if (total == 0) 0 else correct * 100 / total
class ScoreTest {
@Test
fun percent_isRoundedDown() {
assertEquals(66, percent(correct = 2, total = 3))
}
@Test
fun percent_withNoQuestions_isZero() {
assertEquals(0, percent(correct = 0, total = 0))
}
}src/test. Целочисленное деление отбрасывает дробную часть: 200 / 3 = 66.class QuizScreenTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun correctAnswer_movesToNextQuestion() {
composeTestRule.setContent { QuizScreen() }
composeTestRule.onNodeWithText("Question 1 of 5").assertIsDisplayed()
composeTestRule.onNodeWithText("Correct").performClick()
composeTestRule.onNodeWithText("Question 2 of 5").assertIsDisplayed()
}
}src/androidTest: тест сам нажимает кнопку и проверяет, что экран изменился.Доступность и производительность
Пользователи со слабым зрением работают с приложением через экранный диктор TalkBack, который вслух читает элементы экрана. Для значков без текста задавай contentDescription, а для декоративных картинок передавай null, чтобы диктор их пропускал. Области нажатия должны быть не меньше 48×48 dp (компоненты Material это обеспечивают), а размер текста задаётся в sp, чтобы текст увеличивался при выборе крупного шрифта в системе.
IconButton(onClick = onDelete) {
Icon(
painter = painterResource(R.drawable.ic_delete),
contentDescription = null
)
}IconButton(onClick = onDelete) {
Icon(
painter = painterResource(R.drawable.ic_delete),
contentDescription = stringResource(R.string.delete_lesson)
)
}strings.xml, поэтому переводится на каждый язык.- Скорость всегда измеряй в релизной сборке: в отладочной (debug) Compose работает заметно медленнее.
- Тяжёлые вычисления выполняй во ViewModel или один раз через
remember, а не прямо в composable. - Baseline Profile ускоряет запуск приложения и первые экраны; в Android Studio есть готовый шаблон модуля для него.
- Доступность проверяй приложением Accessibility Scanner, а скорость — окном Profiler в Android Studio.
Ctrl+Shift+R)Ctrl+Shift+F10Cmd+Shift+T)Ctrl+Shift+TCtrl+Option+O)Ctrl+Alt+OCmd+Option+L)Ctrl+Alt+LГлавное
versionCode— целое число, растущее с каждой загрузкой, аversionName— видимая пользователю строка вроде0.1.0.- Новые приложения загружаются как подписанный
.aab; для пользователей подпись ставит Play App Signing. - В Play Console заполняют страницу в магазине, содержание приложения и тестовые треки; новым личным аккаунтам нужен 14-дневный закрытый тест с 12 тестировщиками.
- Модульные тесты пишут в
src/test, UI-тесты Compose — вsrc/androidTest. - Давай значкам
contentDescription, задавай размер текста вspи проверяй скорость только в релизной сборке.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.