f68ea10342
signingConfigs в app-phone/app-glasses берут кестор и креды из скилла android-sign (вне git); без кестора release собирается без подписи. assembleSigned — собрать оба приложения одним шагом.
173 lines
7.3 KiB
Kotlin
173 lines
7.3 KiB
Kotlin
import java.util.Properties
|
|
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<String, String> =
|
|
(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() })
|
|
|
|
// LLM-ключ из local.properties (llm.apiKey) — файл вне git; пустой = ещё не задан.
|
|
// providers.gradleProperty не читает local.properties, поэтому грузим файл вручную.
|
|
val llmApiKey: String = run {
|
|
val props = Properties()
|
|
val local = rootProject.file("local.properties")
|
|
if (local.exists()) local.inputStream().use(props::load)
|
|
props.getProperty("llm.apiKey", "")
|
|
.replace("\\", "\\\\")
|
|
.replace("\"", "\\\"")
|
|
}
|
|
|
|
// Модель для ассистента — из local.properties (llm.model), вне git.
|
|
// Дефолт — быстрая дешёвая (пользователь укажет боевую).
|
|
val llmModel: String = run {
|
|
val props = Properties()
|
|
val local = rootProject.file("local.properties")
|
|
if (local.exists()) local.inputStream().use(props::load)
|
|
props.getProperty("llm.model", "Routerai/deepseek/deepseek-v4-flash-0731")
|
|
.replace("\\", "\\\\")
|
|
.replace("\"", "\\\"")
|
|
}
|
|
|
|
android {
|
|
namespace = "pw.binom.viewmate.phone"
|
|
compileSdk = 35
|
|
|
|
defaultConfig {
|
|
applicationId = "pw.binom.viewmate.phone"
|
|
minSdk = 26
|
|
targetSdk = 34
|
|
versionCode = (project.findProperty("versionCode") as? String)?.toIntOrNull() ?: 1
|
|
versionName = (project.findProperty("versionName") as? String) ?: "0.1.0"
|
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
|
|
// LLM-ключ из local.properties (llm.apiKey) — вне git; пустой = ещё не задан
|
|
buildConfigField("String", "LLM_API_KEY", "\"$llmApiKey\"")
|
|
// Модель ассистента — из local.properties (llm.model), вне git
|
|
buildConfigField("String", "LLM_MODEL", "\"$llmModel\"")
|
|
}
|
|
|
|
// Подпись 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
|
|
buildConfig = true
|
|
}
|
|
|
|
packaging {
|
|
resources {
|
|
// okhttp-sse 5.x и jspecify оба кладут этот OSGI-manifest
|
|
excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
dependencies {
|
|
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("androidx.compose.ui:ui")
|
|
implementation("androidx.compose.foundation:foundation")
|
|
implementation("io.coil-kt:coil-compose:2.6.0")
|
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
|
implementation(libs.exoplayer)
|
|
implementation(libs.media3.exoplayer)
|
|
implementation(libs.kotlinx.coroutines.android)
|
|
implementation(libs.kotlinx.serialization.json)
|
|
implementation(project(":lib-core"))
|
|
|
|
// RayNeo Mercury BLE protocol (RayNeo X2): pair/connect/команды с телефона
|
|
implementation("pw.binom.mercury:rayneo-mercury:0.1.0-SNAPSHOT")
|
|
|
|
// QR-код для паринга очков (pairCode) — рендер BitMatrix->Bitmap
|
|
implementation("com.google.zxing:core:3.5.2")
|
|
|
|
// Koog (JetBrains) — LLM-клиент (OpenAI-совместимый)
|
|
implementation(libs.koog.openai.client)
|
|
implementation(libs.koog.http.client.okhttp)
|
|
|
|
// LiteRT-LM (Google) — локальный LLM (Gemma 4 E2B, .litertlm, GPU/CPU):
|
|
// KMP-обёртка pw.binom.litert (универсальный контракт RAW-инференса + google-бэкенд)
|
|
implementation(libs.litert.google)
|
|
// универсальный контракт (LiteLlm/LiteRequest…) — импортируется напрямую
|
|
implementation(libs.litert.api)
|
|
|
|
// Silero-VAD на sherpa-onnx (SherpaStreamingVad / VadSegmenter), JitPack
|
|
implementation("com.github.k2-fsa.sherpa-onnx:sherpa-onnx:v1.13.6")
|
|
|
|
// Офлайн-распознавание Qwen3-ASR (asr-kmp, caffeine nexus) — Qwen3AsrStt
|
|
implementation("pw.binom.asr:asr-qwen3-android:4")
|
|
|
|
// WS-сервер телефона (CIO — работает на Android)
|
|
implementation("io.ktor:ktor-server-core:3.3.0")
|
|
implementation("io.ktor:ktor-server-cio:3.3.0")
|
|
implementation("io.ktor:ktor-server-websockets:3.3.0")
|
|
implementation("io.ktor:ktor-serialization-kotlinx-json:3.3.0")
|
|
|
|
testImplementation(kotlin("test"))
|
|
// Тестовый стриминговый VAD (Silero на ONNX, JVM) — из mavenLocal
|
|
testImplementation("pw.binom.ai.voice:vad-jvm:1.0.0-SNAPSHOT")
|
|
testImplementation("io.ktor:ktor-server-test-host:3.3.0")
|
|
testImplementation("io.ktor:ktor-client-websockets:3.3.0")
|
|
testImplementation("io.ktor:ktor-client-content-negotiation:3.3.0")
|
|
testImplementation("io.ktor:ktor-serialization-kotlinx-json:3.3.0")
|
|
testImplementation(libs.kotlinx.coroutines.test)
|
|
|
|
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
|
androidTestImplementation("androidx.test:runner:1.6.2")
|
|
}
|