Files
f7cloud_mobile/app/build.gradle
T
b-dev-mobile 321f81bffe Этап 0 п.3 (доп): биометрическая привязка app password поверх шифрования
Auth-bound RSA-пара `f7_auth_master_bio` в AndroidKeystore
(setUserAuthenticationRequired + setInvalidatedByBiometricEnrollment,
per-use CryptoObject, префикс v2b:): ПУБЛИЧНЫЙ ключ шифрует без авторизации
(в т.ч. в фоне — миграция/сохранение после входа), ПРИВАТНЫЙ расшифровывает
ТОЛЬКО через BiometricPrompt+CryptoObject. Симметричный AES не подошёл бы:
там auth требуется и на шифрование.

Разрешение конфликта с фоновыми push/звонками: пароль расшифровывается ОДИН
раз при разблокировке (AppLockGate) и живёт в памяти процесса
(AppPasswordHolder, не на диске). AuthStore.load() в фоне возвращает null,
пока «холодно» → существующие `?: return` в push/звонках деградируют сами;
экраны Accept (CallIncomingActivity, TalkPushBridge) открывают приложение
для разблокировки вместо тихого отказа. AppScaffold через loadMetadata()
показывает экран блокировки, а не логин, и перечитывает сессию после разблокировки.

ВЫКЛ по умолчанию (AppLockStore.isPasswordBindingEnabled, только при
биометрии-без-PIN — единственный путь разблокировки прогревает holder).
UI-тумблер и включение по умолчанию — ПОСЛЕ подтверждения владельцем поведения
«после ребута до первой разблокировки звонки/push не работают» (как в Signal).

v0.5.115 (123). Проверено сборкой assembleRelease на инфре B: APK 54.6 МБ,
подпись v2+v3 OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:49:45 +00:00

138 lines
6.1 KiB
Groovy

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.compose'
}
def googleServicesFile = file('google-services.json')
if (googleServicesFile.exists()) {
apply plugin: 'com.google.gms.google-services'
}
// Release-подпись читается из окружения/gradle-properties (боевой keystore вне git,
// в CI — из secrets). Переменные: F7_KEYSTORE_FILE, F7_KEYSTORE_PASSWORD,
// F7_KEY_ALIAS, F7_KEY_PASSWORD (можно и как -P… gradle-property). Если не заданы —
// release подписывается debug-ключом (локальная сборка/QA работает без keystore).
def f7KeystoreFile = System.getenv('F7_KEYSTORE_FILE') ?: project.findProperty('F7_KEYSTORE_FILE')
def f7HasReleaseSigning = f7KeystoreFile != null && file(f7KeystoreFile).exists()
android {
namespace 'ru.forbion.f7cloud.mobile'
compileSdk 36
signingConfigs {
if (f7HasReleaseSigning) {
release {
storeFile file(f7KeystoreFile)
storePassword System.getenv('F7_KEYSTORE_PASSWORD') ?: project.findProperty('F7_KEYSTORE_PASSWORD')
keyAlias System.getenv('F7_KEY_ALIAS') ?: project.findProperty('F7_KEY_ALIAS')
keyPassword System.getenv('F7_KEY_PASSWORD') ?: project.findProperty('F7_KEY_PASSWORD')
// v2 обязателен (minSdk 26); v3 — под будущую ротацию ключа. v1 не нужен (minSdk>=24).
enableV1Signing false
enableV2Signing true
enableV3Signing true
}
}
}
defaultConfig {
applicationId 'ru.forbion.f7cloud.mobile'
minSdk 26
targetSdk 36
versionCode 123
versionName '0.5.115'
missingDimensionStrategy 'default', 'f7'
multiDexEnabled true
// Универсальный APK для реальных устройств: только ARM (arm64 + armeabi-v7a),
// без эмуляторных x86/x86_64 — режет ~половину native-веса (WebRTC .so).
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
// Оставляем только нужные локали (у vendor-форка ~48 языков) — минус несколько МБ.
// resourceConfigurations — не-deprecated бэкинг resConfigs.
resourceConfigurations += ['ru', 'en']
// Дефолтный адрес сервера на экране входа. Прод-URL в сборку не вшивать
// (решение integrator-b, f7_platform mail/035): для дев-сборки под свой
// стенд задать -Pf7DefaultServerUrl=https://... или f7DefaultServerUrl в
// ~/.gradle/gradle.properties. Без свойства поле входа пустое.
buildConfigField 'String', 'DEFAULT_SERVER_URL',
"\"${project.findProperty('f7DefaultServerUrl') ?: ''}\""
}
buildTypes {
debug {}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// боевой keystore — если задан env/-P; иначе debug-ключ (не для распространения)
signingConfig f7HasReleaseSigning ? signingConfigs.release : signingConfigs.debug
}
}
buildFeatures {
compose true
buildConfig true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
applicationVariants.configureEach { variant ->
variant.outputs.configureEach { output ->
def vName = variant.versionName ?: "0.0.0"
def vCode = variant.versionCode ?: 0
output.outputFileName = "f7cloud-mobile-v${vName}-${vCode}-${variant.name}.apk"
}
}
}
dependencies {
implementation project(':core:auth')
implementation project(':core:network')
implementation project(':core:push')
implementation project(':core:designsystem')
implementation project(':feature:files')
implementation project(':feature:talk')
implementation project(':feature:talk-native')
implementation project(':feature:calendar')
implementation project(':feature:contacts')
implementation project(':feature:tasks')
implementation project(':feature:deck')
implementation project(':feature:mail')
implementation project(':feature:f7support')
def composeBom = platform('androidx.compose:compose-bom:2025.02.00')
implementation composeBom
androidTestImplementation composeBom
implementation 'androidx.activity:activity-compose:1.10.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.navigation:navigation-compose:2.8.9'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7'
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.7'
implementation 'androidx.lifecycle:lifecycle-process:2.8.7'
implementation 'io.coil-kt:coil-compose:2.7.0'
implementation 'io.coil-kt:coil-svg:2.7.0'
implementation platform('com.google.firebase:firebase-bom:33.7.0')
implementation 'com.google.firebase:firebase-messaging'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'androidx.fragment:fragment-ktx:1.8.6'
implementation 'androidx.camera:camera-camera2:1.5.2'
implementation 'androidx.camera:camera-lifecycle:1.5.2'
implementation 'androidx.camera:camera-view:1.5.2'
implementation 'com.google.zxing:core:3.3.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'com.google.guava:guava:33.3.1-android'
debugImplementation 'androidx.compose.ui:ui-tooling'
}