# Release-подпись и минификация f7cloud_mobile ## TL;DR `assembleRelease` теперь собирает **подписанный, минифицированный** APK. Ключ подписи берётся из окружения; при его отсутствии release подписывается debug-ключом (для локального QA). ## Переменные окружения (боевой keystore — вне git, в CI — из secrets) | Переменная | Назначение | |---|---| | `F7_KEYSTORE_FILE` | путь к keystore (`.jks`/`.p12`) | | `F7_KEYSTORE_PASSWORD` | пароль хранилища | | `F7_KEY_ALIAS` | алиас ключа | | `F7_KEY_PASSWORD` | пароль ключа | Можно задавать и как gradle-property (`-PF7_KEYSTORE_FILE=…`). Логика — в `app/build.gradle` (`signingConfigs.release`): если `F7_KEYSTORE_FILE` задан и файл существует → подпись боевым ключом (схемы v2+v3, v1 отключён — minSdk 26); иначе → debug-ключ (APK **не для распространения**). ## Генерация боевого keystore (один раз, хранить в секрете и с бэкапом!) ```bash keytool -genkeypair -v \ -keystore f7cloud-release.p12 -storetype PKCS12 \ -alias f7cloud -keyalg RSA -keysize 4096 -validity 10000 \ -dname "CN=F7cloud Mobile, O=F7cloud, C=RU" ``` ⚠️ **PKCS12 (дефолт современного keytool): пароль ключа ОБЯЗАН совпадать с паролем хранилища.** Отдельный `-keypass` игнорируется → при сборке `KeytoolException: Given final block not properly padded`. Поэтому `F7_KEY_PASSWORD == F7_KEYSTORE_PASSWORD`. ⚠️ Боевой ключ подписи **неизменен на весь срок жизни приложения**: потеря = невозможность выката обновлений существующим пользователям. Хранить в секрете + офлайн-бэкап. ## Локальная сборка (пример) ```bash export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 export ANDROID_HOME=/opt/android-sdk source /path/to/signing.env # экспорт четырёх F7_* переменных ./gradlew :app:assembleRelease # APK: app/build/outputs/apk/release/f7cloud-mobile-v--release.apk # проверка: $ANDROID_HOME/build-tools/36.0.0/apksigner verify --verbose ``` ## Минификация (R8) Release: `minifyEnabled true` + `shrinkResources true`. Keep-правила: - **app-уровень** — `app/proguard-rules.pro` (kotlinx.serialization, Firebase, JS-мосты WebView, Coil). - **vendor-зависимости** — `vendor/talk-android/app/consumer-rules.pro`, подключён через `consumerProguardFiles` (WebRTC JNI, LoganSquare `$$JsonObjectMapper`, Dagger, RxJava, Parceler, EventBus, conscrypt + `-dontwarn` geogson/joda). Vendor — library без своей минификации, поэтому его правила доезжают до R8 приложения ТОЛЬКО через consumer-файл. При добавлении рефлексивных библиотек: собрать release, при `Missing class` R8 сгенерирует точные правила в `app/build/intermediates/mapping/release/minifyReleaseWithR8/missing_rules.txt` — перенести их в соответствующий proguard-файл. ## Размер APK Прогресс сокращения (универсальный APK): - **~130 МБ** — debug (все 4 ABI, без R8). - **99 МБ** — release: R8 + shrinkResources (все 4 ABI). - **53 МБ** — + `abiFilters 'arm64-v8a','armeabi-v7a'` (без эмуляторных x86/x86_64) + `resourceConfigurations += ['ru','en']`. Это ТЕКУЩИЙ универсальный APK (пункт 2 этапа 0). Состав .so в 53-МБ APK: arm64-v8a ~19 МБ + armeabi-v7a ~11 МБ (в основном WebRTC). Настройки — в `app/build.gradle` (`defaultConfig.ndk.abiFilters`, `resourceConfigurations`). Ещё возможно (НЕ сделано, требует проверки на устройстве): только arm64 (−~11 МБ, теряет 32-битные устройства); отключить `renderscriptSupportModeEnabled` в vendor (риск для blur-эффектов).