import java.util.Properties plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } // Signing credentials are NEVER committed. They are read from (in order): // 1. environment variables (KEYSTORE_PASSWORD / KEY_PASSWORD / KEY_ALIAS) — used by CI // 2. keystore.properties at the repo root (gitignored) — used locally // See keystore.properties.example. Debug builds need none of this. val keystoreProps = Properties().apply { val f = rootProject.file("keystore.properties") if (f.exists()) f.inputStream().use { load(it) } } fun signingCred(envName: String, propName: String): String? = System.getenv(envName) ?: keystoreProps.getProperty(propName) android { namespace = "me.khodak.claudeusage" compileSdk = 34 defaultConfig { applicationId = "me.khodak.claudeusage" minSdk = 26 targetSdk = 34 versionCode = 19 versionName = "1.18" } val releaseStorePassword = signingCred("KEYSTORE_PASSWORD", "storePassword") val releaseKeyPassword = signingCred("KEY_PASSWORD", "keyPassword") val releaseKeyAlias = signingCred("KEY_ALIAS", "keyAlias") ?: "claudewidget" val hasSigningCreds = releaseStorePassword != null && releaseKeyPassword != null signingConfigs { create("release") { // Only wire the keystore when credentials are present, so debug builds and // credential-less checkouts configure cleanly. Same keystore file + alias as before — // signing identity is unchanged; only the password source moved out of version control. if (hasSigningCreds) { storeFile = file("claude-widget-release.keystore") storePassword = releaseStorePassword keyAlias = releaseKeyAlias keyPassword = releaseKeyPassword } } } buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") // Sign only when creds were supplied; otherwise fail loudly at assembleRelease rather // than silently shipping an unsigned APK. Tag builds in CI inject creds (see workflow). if (hasSigningCreds) { signingConfig = signingConfigs.getByName("release") } else { logger.warn("No signing credentials (KEYSTORE_PASSWORD/keystore.properties) — release APK will be unsigned.") } } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" } buildFeatures { viewBinding = true buildConfig = true } } dependencies { implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.11.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") // HTTP implementation("com.squareup.okhttp3:okhttp:4.12.0") // JSON implementation("com.google.code.gson:gson:2.10.1") // Background work implementation("androidx.work:work-runtime-ktx:2.9.0") // Secure storage implementation("androidx.security:security-crypto:1.1.0-alpha06") // Coroutines implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Lifecycle implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") }