import java.io.File plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlinx.serialization) alias(libs.plugins.compose.compiler) } // Подпись release ключом Binom (assembleRelease сам подпишет APK, v2+v3). Кестор + креды — // из скилла android-sign (вне git); переопределение: -Pbinom.keystore.dir=... / env BINOM_KEYSTORE_DIR. val binomCertsDir: File = File( (project.findProperty("binom.keystore.dir") as? String) ?: System.getenv("BINOM_KEYSTORE_DIR") ?: "${System.getProperty("user.home")}/.config/opencode/skills/android-sign/certs" ) val binomStoreFile = File(binomCertsDir, "android-release.keystore") val binomCreds: Map = (File(binomCertsDir, "creds.env").let { c -> if (binomStoreFile.exists() && c.exists()) c.readLines().filter { it.isNotBlank() && !it.startsWith("#") && it.contains('=') } .associate { val i = it.indexOf('='); it.substring(0, i) to it.substring(i + 1).trim().removeSurrounding("\"") } else emptyMap() }) android { namespace = "pw.binom.viewmate.glasses" compileSdk = 35 defaultConfig { applicationId = "pw.binom.viewmate.glasses" minSdk = 26 targetSdk = 34 versionCode = (project.findProperty("versionCode") as? String)?.toIntOrNull() ?: 1 versionName = (project.findProperty("versionName") as? String) ?: "0.1.0" } // Подпись release ключом Binom (всё из binomStoreFile/binomCreds выше). // Без кестора binomCreds пусто → release остаётся неподписанным. if (binomCreds.isNotEmpty()) { val binomAlias = binomCreds.getValue("ANDROID_KEYSTORE_ALIAS") val binomStorePass = binomCreds.getValue("ANDROID_KEYSTORE_PASSWORD") val binomKeyPass = binomCreds["ANDROID_KEY_PASSWORD"] ?: binomStorePass signingConfigs { create("binom") { storeFile = binomStoreFile storePassword = binomStorePass keyAlias = binomAlias keyPassword = binomKeyPass enableV1Signing = false enableV2Signing = true enableV3Signing = true } } } buildTypes { release { isMinifyEnabled = false if (binomCreds.isNotEmpty()) { signingConfig = signingConfigs.getByName("binom") } } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) } } buildFeatures { compose = true } testOptions { // Unit-тесты строят TempleAction из aar, чьи конструкторы дёргают // SystemClock.uptimeMillis() — unmocked методы android.jar возвращают // значения по умолчанию вместо "not mocked". unitTests.isReturnDefaultValues = true } } dependencies { // RayNeo SDK (локальный aar) implementation(fileTree("libs")) implementation("androidx.appcompat:appcompat:1.3.0") implementation("androidx.core:core-ktx:1.7.0") implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.android.material3) implementation(libs.exoplayer) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.serialization.json) implementation(project(":lib-core")) implementation("com.squareup.okhttp3:okhttp:4.12.0") // Локальный Qwen3-ASR на очках (движок + распознавание переезжают на очки из app-phone). // asr-qwen3-android тянет sherpa-onnx (nativ) транзитивно; модель — в filesDir/models // (SttModelProvider), как на телефоне. implementation("pw.binom.asr:asr-qwen3-android:4") // VAD на очках (WebRTC VAD — лёгкий, без моделей; схема pair-view автора) // VAD (WebRTC) убран из прода: резал речь на рваном микрофоне ARGT78 — // whisper распознаёт полный поток без VAD (проверено на сыром дампе). // implementation("com.github.gkonovalov.android-vad:webrtc:2.0.10") // WS-клиент очков (OkHttp — Android-движок) implementation(libs.ktor.client.okhttp) implementation(libs.ktor.client.websockets) testImplementation(kotlin("test")) }