Перейти к основному содержимому

Публикация Android-приложения

Разработчику Архитектору Инженеру

От сборки к публикации

Публикация в Store - отдельный контур работ

Когда проект собран в конфигурации release, остаётся два обязательных шага: подписать артефакт (APK или AAB) собственным ключом и выбрать канал распространения. Теория форматов пакетов, Play App Signing и CI/CD описана в статье Сборка и развёртывание мобильных приложений. Здесь — практическое руководство: создание keystore, настройка Gradle, сравнение магазинов и раздача APK с сайта.

Типичная ошибка новичка: загрузить в магазин или на сайт файл, подписанный отладочным ключом (debug.keystore). Такой ключ одинаков у всех разработчиков Android Studio, не привязан к вам лично и не подходит для продакшена. Google Play отклоняет такие сборки; RuStore и ручная установка формально допускают APK, но обновления «поверх» другой подписи невозможны — пользователю придётся удалить старую версию.


Отладочная и релизная подпись

ПараметрDebugRelease
Файл ключей~/.android/debug.keystore (создаётся автоматически)Ваш .jks / .keystore, созданный вручную
Пароль по умолчаниюandroidЗадаёте вы
AliasandroiddebugkeyНапример, my-key-alias
НазначениеЗапуск с IDE, USB-отладкаМагазины, сайт, корпоративная раздача
Обновления в магазинеНельзя использовать для публикацииОдин ключ на всё время жизни пакета (applicationId)

Правило: для любой сборки, которую увидят пользователи вне вашей машины, нужен release keystore. Потеря файла и пароля означает, что вы не сможете выпускать обновления того же приложения в магазине — только новый пакет с другим applicationId (фактически новое приложение).

Если приложение уже опубликовано с debug-ключом, сменить подпись на release для тех же установок нельзя. Решения: не публиковали в прод — начать с release; уже в проде с debug — новый applicationId и новый ключ (потеря установок) или обращение в поддержку магазина (исключение, редко).


Создание release keystore

Keystore — файл (.jks или .keystore) с закрытым ключом и сертификатом. Храните копию в надёжном месте (менеджер паролей, зашифрованный архив), не коммитьте в Git.

Способ 1 — командная строка (keytool)

В каталоге проекта Android (или в любом месте, указав полный путь к файлу) выполните:

keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.jks -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

На Windows в PowerShell команда та же; keytool входит в JDK (часто: "%JAVA_HOME%\bin\keytool").

Параметры:

  • -keystore — имя создаваемого файла;
  • -alias — имя ключа внутри хранилища (понадобится в Gradle);
  • -validity — срок в днях (10000 ≈ 27 лет);
  • при запросе CN, организации и т.д. можно указать реальные или условные данные — они попадут в сертификат.

Задайте два пароля: на хранилище и на ключ (часто совпадают). Запомните alias.

Способ 2 — Android Studio

Build → Generate Signed Bundle / APK → Android App Bundle (или APK) → NextCreate new... — укажите путь, пароли, alias и срок действия. Studio создаст keystore и может сразу собрать подписанный артефакт.


Настройка Gradle

Пароли и путь к keystore не должны лежать в открытом виде в build.gradle, если репозиторий публичный. Стандартный вариант — local.properties (уже в .gitignore у типового Android-проекта) или переменные окружения CI.

Пример local.properties (файл в корне проекта, рядом с settings.gradle):

RELEASE_STORE_FILE=../keystore/my-release-key.jks
RELEASE_STORE_PASSWORD=ваш_пароль_хранилища
RELEASE_KEY_ALIAS=my-key-alias
RELEASE_KEY_PASSWORD=ваш_пароль_ключа

Путь RELEASE_STORE_FILE — относительно модуля app или абсолютный.

Groovy (app/build.gradle)

def keystorePropertiesFile = rootProject.file("local.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
signingConfigs {
release {
storeFile file(keystoreProperties['RELEASE_STORE_FILE'])
storePassword keystoreProperties['RELEASE_STORE_PASSWORD']
keyAlias keystoreProperties['RELEASE_KEY_ALIAS']
keyPassword keystoreProperties['RELEASE_KEY_PASSWORD']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

Kotlin DSL (app/build.gradle.kts)

val keystorePropertiesFile = rootProject.file("local.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(keystorePropertiesFile.inputStream())
}

android {
signingConfigs {
create("release") {
storeFile = file(keystoreProperties["RELEASE_STORE_FILE"] as String)
storePassword = keystoreProperties["RELEASE_STORE_PASSWORD"] as String
keyAlias = keystoreProperties["RELEASE_KEY_ALIAS"] as String
keyPassword = keystoreProperties["RELEASE_KEY_PASSWORD"] as String
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}

В CI вместо local.properties передают те же имена через секреты: RELEASE_STORE_FILE, пароли — как зашифрованные переменные пайплайна.


Сборка подписанного APK и AAB

Из корня проекта Android:

# Linux / macOS
./gradlew assembleRelease
./gradlew bundleRelease

# Windows
gradlew.bat assembleRelease
gradlew.bat bundleRelease

Результаты (пути могут отличаться по версии AGP):

  • APK: app/build/outputs/apk/release/app-release.apk
  • AAB: app/build/outputs/bundle/release/app-release.aab

Перед загрузкой увеличивайте в build.gradle модуля app:

  • versionCode — целое, строго больше предыдущей публикации (иначе INSTALL_FAILED_VERSION_DOWNGRADE);
  • versionName — строка для людей (1.0.1).

Для Google Play предпочтителен AAB; для RuStore, сайта и прямой установки часто достаточно одного универсального APK.


Проверка подписи

Убедитесь, что подпись не отладочная:

apksigner verify --verbose app/build/outputs/apk/release/app-release.apk

Требуется Android SDK Build-Tools (apksigner в build-tools/<version>/).

Сравнить отпечаток сертификата release и debug:

keytool -list -v -keystore my-release-key.jks -alias my-key-alias
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android

SHA-256 в выводе должны различаться. Тот же SHA-256 можно опубликовать на странице загрузки на сайте — пользователь сверит подпись установленного APK через настройки Android → «О приложении» → сертификаты.

Для AAB: Bundle Explorer или загрузка в Play Console / внутренний трек — в карточке виден сертификат upload key.


Куда публиковать — сравнение каналов

КритерийСайт (прямой APK)RuStoreGoogle PlayApp Store (iOS)
Вход для разработчика0 ₽0 ₽~$25 (единоразово)~$99/год
Оплата из РФНе нужнаОбычно без проблемЧасто сложно (карта, валюта)Часто сложно
ФорматAPK (реже AAB вручную)APK, AABAAB (APK для старых треков)IPA
АвтообновленияНетДа (магазин)ДаДа
Доверие пользователяСреднееВысокое в РФВысокое глобальноОчень высокое
МодерацияНетДаДаСтрогая
Санкции / геоНет привязкиОриентир на РФОграничения для платежей и аккаунтаОграничения для платежей

Практичная стратегия без бюджета на зарубежные магазины: release-сборка → RuStore (основной магазин для аудитории в России) + страница на сайте с APK и контрольной суммой (резервная ссылка, бета, корпоративные пользователи). Google Play — когда появится возможность оплатить аккаунт и нужна глобальная витрина.

Пользователи в России скачивают из Google Play; ограничение для разработчика — регистрация и $25, а не «закрытый магазин» для страны.


RuStore

Консоль разработчика RuStore — регистрация бесплатна, для физлица обычно нужны данные паспорта РФ (для юрлица — ИНН).

Что загружать: готовый APK или AAB, подписанный вашим release-ключом. Исходный код и структура проекта не передаются.

Модерация проверяет:

  • манифест (разрешения, компоненты, applicationId);
  • поведение приложения (запуск, заявленный функционал);
  • соответствие описанию и законодательству РФ;
  • автоматически — вредоносный код.

Что не видят модераторы: ваши .kt / .java файлы и папки проекта. Внутри APK теоретически возможен реверс-инжиниринг байт-кода (как для любого APK в открытом доступе). Поэтому в release включайте R8 (minifyEnabled true) и не храните API-ключи и пароли в коде — см. обфускацию в статье о сборке.

Риски: потеря доступа к аккаунту разработчика; отказ из-за лишних разрешений или несоответствия описанию; извлечение секретов из APK при слабой обфускации. Включите 2FA в кабинете, если доступна.


Раздача APK с сайта

Подходит для проектов без магазина или как дополнение к RuStore.

Структура на сервере (пример):

/downloads/
my-app-1.0.0.apk
my-app-1.0.0.sha256.txt
install-guide.md

Контрольная сумма (Windows PowerShell):

Get-FileHash -Algorithm SHA256 .\my-app-1.0.0.apk

Сохраните строку хеша в .sha256.txt рядом с файлом. На Linux/macOS: sha256sum my-app-1.0.0.apk.

Страница для пользователя должна содержать:

  1. Ссылку на APK и хеш SHA-256.
  2. Минимальную версию Android (minSdkVersion из манифеста).
  3. Шаги: скачать → при необходимости проверить хеш → разрешить установку из этого источника (браузер или «Файлы») → установить.
  4. Краткий дисклеймер «как есть» и ссылку на политику конфиденциальности, если приложение что-то собирает.

Ограничения: нет push об обновлении от магазина; Play Protect может предупредить о «неизвестном» источнике — это нормально для sideload; один универсальный APK проще для пользователя, чем несколько файлов по архитектурам.


Google Play (кратко)

Нужен аккаунт разработчика и оплата регистрации. Загружается AAB, подписанный upload key; при включённом Play App Signing Google хранит app signing key — подробности в 112.md.

Для новых приложений в консоли заполняют карточку, политику конфиденциальности, скриншоты и проходят модерацию. Обновления только с тем же upload key (или по процедуре сброса ключа в консоли).


iOS и альтернатива без App Store

Нативное приложение для iPhone без Apple Developer Program (~$99/год) в App Store не опубликовать. Установка .ipa вне магазина для обычного пользователя без jailbreak практически недоступна.

Варианты без оплаты Apple:

  • PWA — веб-приложение с манифестом и Service Worker; установка через Safari «На экран Домой». Подробнее: PWA в мобильных приложениях.
  • Отложить iOS и сосредоточиться на Android + веб.

TestFlight и Ad Hoc тоже требуют платный аккаунт и ограничены по устройствам.


Чек-лист перед публикацией

  • Сборка release, не debug.
  • Подпись через свой keystore, не debug.keystore.
  • versionCode увеличен относительно предыдущей публикации.
  • minifyEnabled true и правила ProGuard/R8 для кода с reflection.
  • Секреты (API keys, пароли БД) не в исходниках APK.
  • Резервная копия .jks и паролей в безопасном хранилище.
  • Протестирована установка «с нуля» на чистом устройстве.
  • Для сайта: опубликован SHA-256; для магазина: скриншоты и политика конфиденциальности.

Частые ошибки

СимптомПричина
Play отклонил APKDebug-подпись или заниженный versionCode
«App not installed» на телефонеКонфликт подписи с уже установленной версией
R8 сломал reflectionНет keep-правил в proguard-rules.pro
Обновление невозможноПотерян keystore — только новый applicationId

Что попробовать

  1. bundletool — проверьте AAB локально перед загрузкой.
  2. Internal testing track в Play Console — тест без публичного релиза.
  3. RuStore + Google Play — один и тот же release-ключ на оба канала.

Частые ошибки

СимптомПричина
Play отклонил APKDebug-подпись или заниженный versionCode
«App not installed» на телефонеКонфликт подписи с уже установленной версией
R8 сломал reflectionНет keep-правил в proguard-rules.pro
Обновление невозможноПотерян keystore — только новый applicationId

Что попробовать

  1. bundletool — проверьте AAB локально перед загрузкой.
  2. Internal testing track в Play Console — тест без публичного релиза.
  3. RuStore + Google Play — один и тот же release-ключ на оба канала.

Связанные материалы



См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).