plugins { alias(libs.plugins.android.application) } android { namespace 'com.evsuite.abrp' compileSdk { version = release(36) { minorApiLevel = 1 } } // Signature de l'APK — rien à voir avec la clé d'API ABRP de l'utilisateur. // Ces valeurs servent UNIQUEMENT au build : elles prouvent que l'APK vient bien de // nous et n'entrent jamais dans l'application. La clé d'API et le token ABRP, eux, // sont saisis dans l'app et stockés chiffrés sur l'appareil (voir SecurePrefs). // // Un keystore contient plusieurs clés : SIGNING_STORE_PASSWORD ouvre le conteneur, // SIGNING_KEY_ALIAS choisit la clé, SIGNING_KEY_PASSWORD ouvre cette clé-là. // Lues depuis l'environnement (CI) ou gradle.properties local — JAMAIS commitées. 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 76 versionName "2.12.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 quand aucun keystore n'est configuré : le build reste possible sur une // machine sans secrets (APK non signé), au lieu d'échouer. def platformSigning = signingConfigs.findByName("platform") // Deux canaux de distribution : // - stable : diffusé en release taguée, AUCUN auto-update. L'utilisateur installe // lui-même ; rien dans l'app ne va chercher un APK. // - unstable : pré-releases publiées à chaque push sur master, avec OTA pour que les testeurs // soient à jour sans manipulation. Installable à côté du 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 } } // Nomme les APK par canal pour que les artefacts de release soient lisibles. androidComponents { onVariants(selector().all()) { variant -> variant.outputs.each { output -> if (variant.buildType == "release") { // Le canal unstable garde un nom de fichier stable : l'updater identifie // la version par le tag de la pré-release, jamais par le nom d'APK. 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 }