Files
mg4/app/build.gradle
nilsandClaude Opus 5.5 496fb821c3 App 2.18.1: every tab fits the car's window without scrolling
Charging and Consumption get two-column wide layouts; Live data and
Settings are tightened (fields beside their buttons, button rows,
16 dp vertical card padding). Checked on the emulator at 1778x640.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 22:11:05 +02:00

149 lines
6.1 KiB
Groovy

plugins {
alias(libs.plugins.android.application)
}
android {
namespace 'com.evsuite.abrp'
compileSdk {
version = release(36) {
minorApiLevel = 1
}
}
// APK signing — nothing to do with the user's ABRP credentials. These values are ONLY for
// the build: they prove the APK comes from us and never enter the app. The ABRP API key and
// token are entered in the app and stored encrypted on the device (see SecurePrefs).
// The car build is signed by build-car (flake.nix) with the AOSP platform key instead.
//
// A keystore holds several keys: SIGNING_STORE_PASSWORD opens the container,
// SIGNING_KEY_ALIAS picks the key, SIGNING_KEY_PASSWORD opens that key.
// Read from the environment (CI) or a local gradle.properties — NEVER committed.
def keystorePath = System.getenv("SIGNING_KEYSTORE") ?: project.findProperty("signing.keystore")
signingConfigs {
if (keystorePath != null && file(keystorePath).exists()) {
platform {
storeFile file(keystorePath)
storePassword System.getenv("SIGNING_STORE_PASSWORD") ?: project.findProperty("signing.store.password")
keyAlias System.getenv("SIGNING_KEY_ALIAS") ?: project.findProperty("signing.key.alias") ?: "platform"
keyPassword System.getenv("SIGNING_KEY_PASSWORD") ?: project.findProperty("signing.key.password")
}
}
}
defaultConfig {
applicationId "com.stinnesbeck.nilsmg4"
minSdk 27
targetSdk 36
versionCode 96
versionName "2.18.1"
// Nothing about the server ships in the APK: its URL and ingest token are entered in
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// null when no keystore is configured: the build still works on a machine without
// secrets (unsigned APK) instead of failing.
def platformSigning = signingConfigs.findByName("platform")
// Two distribution channels:
// - stable: no self-update at all. The user installs it; nothing in the app fetches an
// APK (the updater is not even in this APK).
// - unstable: the car build (system UID, platform-signed), with the OTA updater, so the
// car can update itself from published pre-releases. Installs next to stable.
flavorDimensions += "channel"
productFlavors {
stable {
dimension "channel"
buildConfigField "boolean", "OTA_ENABLED", "false"
}
unstable {
dimension "channel"
applicationIdSuffix ".unstable"
// Three-part versions, the same as defaultConfig ("2.8.1-unstable"). Upstream added
// a fourth part for its CI build number; there is no CI here and the OTA updater is
// off. The version code keeps upstream's x100000 so it never drops below codes
// already installed on the car (2.8.0.0 was 6600000): a lower code is a downgrade,
// which the installer refuses.
versionCode defaultConfig.versionCode * 100000
versionName defaultConfig.versionName
versionNameSuffix "-unstable"
buildConfigField "boolean", "OTA_ENABLED", "true"
}
}
buildTypes {
debug {
if (platformSigning != null) signingConfig platformSigning
}
release {
// [T-918] R8 enabled. CarPropertyAdapter reaches the car purely by
// reflection, so proguard-rules.pro must keep those targets; a release build
// needs an on-vehicle check of the car reads before it ships.
minifyEnabled true
if (platformSigning != null) signingConfig platformSigning
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// BuildConfig.DEBUG gates the debug-only logging (T-912).
buildFeatures {
buildConfig true
}
lint {
abortOnError true
checkReleaseBuilds true
warningsAsErrors false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
// The version build-car puts in the APK's file name ("NilsMG4-unstable-2.8.1.apk"), which
// is also the name the OTA updater reads a release's version from.
tasks.register('printUnstableVersion') {
doLast {
println android.defaultConfig.versionName
}
}
// Names the APKs by channel so the build outputs are readable.
androidComponents {
onVariants(selector().all()) { variant ->
variant.outputs.each { output ->
if (variant.buildType == "release") {
// A fixed name for the unstable release output. What is published for the car
// comes from build-car, named NilsMG4-unstable-<version>.apk: that file name is
// where the updater reads a release's version from.
output.outputFileName.set(variant.flavorName == "unstable"
? "NilsMG4-unstable.apk"
: "NilsMG4-${variant.flavorName}-${output.versionName.get()}.apk")
} else {
// Debug builds: NilsMG4-stable-debug.apk, NilsMG4-unstable-debug.apk.
output.outputFileName.set("NilsMG4-${variant.flavorName}-${variant.buildType}.apk")
}
}
}
}
dependencies {
implementation project(':evhardware')
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
implementation libs.viewpager2
implementation libs.security.crypto
implementation 'com.google.zxing:core:3.5.3'
// android.jar's org.json is a stub in unit tests; the real implementation lets the
// telemetry payload tests parse what the app actually builds.
testImplementation libs.junit
testImplementation libs.json
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}