From 8d279afb101084cdb4b86783a5bfef822d6abc49 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sat, 7 Jun 2025 10:43:50 +0000 Subject: [PATCH] Refactor: Migrate app build.gradle to Kotlin DSL (#2046) --- .github/workflows/android.yml | 16 +- .github/workflows/release.yml | 4 +- app/{build.gradle => build.gradle.kts} | 300 +++++++++++++------------ app/proguard-rules.pro | 2 +- gradle/libs.versions.toml | 9 +- 5 files changed, 173 insertions(+), 158 deletions(-) rename app/{build.gradle => build.gradle.kts} (54%) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 7e2ed63fc..a829c781e 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -32,11 +32,11 @@ jobs: - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'zulu' + java-version: '21' + distribution: 'jetbrains' - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 @@ -78,11 +78,11 @@ jobs: with: submodules: 'recursive' - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'zulu' + java-version: '21' + distribution: 'jetbrains' - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 @@ -118,8 +118,8 @@ jobs: - uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'zulu' + java-version: '21' + distribution: 'jetbrains' - uses: gradle/actions/setup-gradle@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f74f8c84..35b2e9bb0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,8 +40,8 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'zulu' + java-version: '21' + distribution: 'jetbrains' # Note: we don't use caches on release builds because we don't want to accidentally not have a virgin build machine - name: Build F-Droid release diff --git a/app/build.gradle b/app/build.gradle.kts similarity index 54% rename from app/build.gradle rename to app/build.gradle.kts index f46a402ec..6376acf3b 100644 --- a/app/build.gradle +++ b/app/build.gradle.kts @@ -1,117 +1,3 @@ -plugins { - alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.compose) - alias(libs.plugins.kotlin.parcelize) - alias(libs.plugins.kotlin.serialization) - alias(libs.plugins.hilt) - alias(libs.plugins.protobuf) - alias(libs.plugins.devtools.ksp) - alias(libs.plugins.detekt) -} - -def keystorePropertiesFile = rootProject.file("keystore.properties") -def keystoreProperties = new Properties() -if (keystorePropertiesFile.exists()) { - keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) -} - -android { - namespace 'com.geeksville.mesh' - - signingConfigs { - release { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null - storePassword keystoreProperties['storePassword'] - } - } - compileSdk Configs.COMPILE_SDK - defaultConfig { - applicationId Configs.APPLICATION_ID - minSdkVersion Configs.MIN_SDK_VERSION - targetSdk Configs.TARGET_SDK - versionCode Configs.VERSION_CODE // format is Mmmss (where M is 1+the numeric major number - versionName Configs.VERSION_NAME - testInstrumentationRunner "com.geeksville.mesh.TestRunner" - buildConfigField("String", "MIN_FW_VERSION", "\"${Configs.MIN_FW_VERSION}\"") - buildConfigField("String", "ABS_MIN_FW_VERSION", "\"${Configs.ABS_MIN_FW_VERSION}\"") - // per https://developer.android.com/studio/write/vector-asset-studio - vectorDrawables.useSupportLibrary = true - } - flavorDimensions = ['default'] - productFlavors { - fdroid { - dimension = 'default' - dependenciesInfo { - includeInApk = false - } - } - google { - dimension = 'default' - if (Configs.USE_CRASHLYTICS) { - apply plugin: 'com.google.gms.google-services' - apply plugin: 'com.google.firebase.crashlytics' - } - } - } - buildTypes { - release { - if (keystoreProperties['storeFile']) { - signingConfig signingConfigs.release - } - minifyEnabled true - shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - pseudoLocalesEnabled true - } - } - defaultConfig { - // We have to list all translated languages here, because some of our libs have bogus languages that google play - // doesn't like and we need to strip them (gr) - resourceConfigurations += ['bg', 'ca', 'cs', 'de', 'el', 'en', 'es', 'et', 'fi', 'fr', 'fr-rHT', 'ga', 'gl', 'hr', 'hu', 'is', 'it', 'iw', 'ja', 'ko', 'lt', 'nl', 'nb', 'pl', 'pt', 'pt-rBR', 'ro', 'ru', 'sk', 'sl', 'sq', 'sr', 'sv', 'tr', 'zh-rCN', 'zh-rTW', 'uk'] - - ndk { - // abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" - } - } - bundle { - language { - enableSplit false - } - } - buildFeatures { - viewBinding true - compose true - aidl true - buildConfig true - } - // Configure the build-logic plugins to target JDK 17 - // This matches the JDK used to build the project, and is not related to what is running on device. - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - freeCompilerArgs += [ - '-opt-in=kotlin.RequiresOptIn', - '-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi' - ] - } - lint { - abortOnError false - disable += "MissingTranslation" - } - sourceSets { - // Adds exported schema location as test app assets. - androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) - } -} - /* * Copyright (c) 2025 Meshtastic LLC * @@ -129,21 +15,149 @@ android { * along with this program. If not, see . */ +import java.io.FileInputStream +import java.util.Properties + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.hilt) + alias(libs.plugins.protobuf) + alias(libs.plugins.devtools.ksp) + alias(libs.plugins.detekt) +} + +val keystorePropertiesFile = rootProject.file("keystore.properties") +val keystoreProperties = Properties() +if (keystorePropertiesFile.exists()) { + FileInputStream(keystorePropertiesFile).use { keystoreProperties.load(it) } +} + +android { + namespace = "com.geeksville.mesh" + + signingConfigs { + create("release") { + keyAlias = keystoreProperties["keyAlias"] as String? + keyPassword = keystoreProperties["keyPassword"] as String? + storeFile = keystoreProperties["storeFile"]?.let { file(it) } + storePassword = keystoreProperties["storePassword"] as String? + } + } + compileSdk = Configs.COMPILE_SDK + defaultConfig { + applicationId = Configs.APPLICATION_ID + minSdk = Configs.MIN_SDK_VERSION + targetSdk = Configs.TARGET_SDK + versionCode = + Configs.VERSION_CODE // format is Mmmss (where M is 1+the numeric major number) + versionName = Configs.VERSION_NAME + testInstrumentationRunner = "com.geeksville.mesh.TestRunner" + buildConfigField("String", "MIN_FW_VERSION", "\"${Configs.MIN_FW_VERSION}\"") + buildConfigField("String", "ABS_MIN_FW_VERSION", "\"${Configs.ABS_MIN_FW_VERSION}\"") + // per https://developer.android.com/studio/write/vector-asset-studio + vectorDrawables.useSupportLibrary = true + } + flavorDimensions.add("default") + productFlavors { + create("fdroid") { + dimension = "default" + dependenciesInfo { + includeInApk = false + } + } + create("google") { + dimension = "default" + if (Configs.USE_CRASHLYTICS) { + // Enable Firebase Crashlytics for Google Play builds + apply(plugin = libs.plugins.google.services.get().pluginId) + apply(plugin = libs.plugins.firebase.crashlytics.get().pluginId) + } + } + } + buildTypes { + named("release") { + if (keystoreProperties["storeFile"] != null) { + signingConfig = signingConfigs.named("release").get() + } + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + named("debug") { + isPseudoLocalesEnabled = true + } + } + defaultConfig { + // We have to list all translated languages here, because some of our libs have bogus languages that google play + // doesn't like and we need to strip them (gr) + androidResources.localeFilters += listOf( + "bg", "ca", "cs", "de", + "el", "en", "es", "et", + "fi", "fr", "fr-rHT", "ga", + "gl", "hr", "hu", "is", + "it", "iw", "ja", "ko", + "lt", "nl", "nb", "pl", + "pt", "pt-rBR", "ro", + "ru", "sk", "sl", "sq", + "sr", "sv", "tr", "zh-rCN", + "zh-rTW", "uk" + ) + + ndk { + abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") + } + } + bundle { + language { + enableSplit = false + } + } + buildFeatures { + viewBinding = true + compose = true + aidl = true + buildConfig = true + } + // Configure the build-logic plugins to target JDK 17 + // This matches the JDK used to build the project, and is not related to what is running on device. + compileOptions { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_21.toString() + freeCompilerArgs += listOf( + "-opt-in=kotlin.RequiresOptIn", + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" + ) + } + lint { + abortOnError = false + disable.add("MissingTranslation") + } + sourceSets { + // Adds exported schema location as test app assets. + named("androidTest") { assets.srcDirs(files("$projectDir/schemas")) } + } +} + // per protobuf-gradle-plugin docs, this is recommended for android protobuf { protoc { - artifact = libs.protobuf.protoc.get() + artifact = libs.protobuf.protoc.get().toString() } generateProtoTasks { - all().each { task -> + all().forEach { task -> task.builtins { - java { - // turned off for now so I can use json printing in debug panel - // use the smaller android version of the library - //option "lite" - } - kotlin { - } + create("java") {} + create("kotlin") {} } } } @@ -151,19 +165,19 @@ protobuf { // workaround for https://github.com/google/ksp/issues/1590 androidComponents { - onVariants(selector().all(), { variant -> - afterEvaluate { - def capName = variant.name.capitalize() + onVariants(selector().all()) { variant -> + project.afterEvaluate { + val capName = variant.name.replaceFirstChar { it.uppercase() } tasks.named("ksp${capName}Kotlin") { dependsOn("generate${capName}Proto") } } - }) + } } dependencies { - implementation project(":network") - implementation(fileTree(dir: 'libs', include: ['*.jar'])) + implementation(project(":network")) + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) // Bundles implementation(libs.bundles.androidx) @@ -178,17 +192,17 @@ dependencies { implementation(libs.bundles.protobuf) implementation(libs.bundles.coil) - //OSM + // OSM implementation(libs.bundles.osm) - implementation(libs.osmdroid.geopackage){ exclude group: "com.j256.ormlite" } + implementation(libs.osmdroid.geopackage) { exclude(group = "com.j256.ormlite") } - //ZXing - implementation(libs.zxing.android.embedded) { transitive = false } - implementation(libs.zxing.core) // do not update + // ZXing + implementation(libs.zxing.android.embedded) { isTransitive = false } + implementation(libs.zxing.core) - //Individual dependencies + // Individual dependencies implementation(libs.appintro) - googleImplementation(libs.awesome.app.rating) + "googleImplementation"(libs.awesome.app.rating) implementation(libs.core.splashscreen) implementation(libs.emoji2.emojipicker) implementation(libs.kotlinx.collections.immutable) @@ -199,20 +213,20 @@ dependencies { implementation(libs.work.runtime.ktx) implementation(libs.core.location.altitude) - //Compose BOM + // Compose BOM implementation(platform(libs.compose.bom)) androidTestImplementation(platform(libs.compose.bom)) - //Firebase BOM - googleImplementation(platform(libs.firebase.bom)) //For Firebase - googleImplementation(libs.bundles.firebase) + // Firebase BOM + "googleImplementation"(platform(libs.firebase.bom)) + "googleImplementation"(libs.bundles.firebase) - //ksp + // ksp ksp(libs.room.compiler) ksp(libs.hilt.compiler) kspAndroidTest(libs.hilt.compiler) - //Testing + // Testing testImplementation(libs.bundles.testing) debugImplementation(libs.bundles.testing.android.manifest) androidTestImplementation(libs.bundles.testing.android) @@ -229,7 +243,7 @@ ksp { } repositories { - maven { url "https://jitpack.io" } + maven { url = uri("https://jitpack.io") } } detekt { diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 77aa35790..165eeb2da 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d1f183a85..cda57da86 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,8 +82,8 @@ espresso-core = { group = "androidx.test.espresso", name = "espresso-core", vers ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit-version" } firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" } -firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics"} -firebase-crashlytics-gradle = { group = "com.google.firebase", name ="firebase-crashlytics-gradle", version.ref = "crashlytics" } +firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } +firebase-crashlytics-gradle = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "crashlytics" } fragment-compose = { module = "androidx.fragment:fragment-compose", version.ref = "fragment-compose" } fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragment-ktx" } google-services = { group = "com.google.gms", name = "google-services", version.ref = "google-services" } @@ -119,7 +119,7 @@ osmdroid-geopackage = { group = "org.osmdroid", name = "osmdroid-geopackage", ve osmdroid-wms = { group = "org.osmdroid", name = "osmdroid-wms", version.ref = "osmdroid-android" } protobuf-gradle-plugin = { group = "com.google.protobuf", name = "protobuf-gradle-plugin", version.ref = "protobuf-gradle-plugin" } protobuf-kotlin = { group = "com.google.protobuf", name = "protobuf-kotlin", version.ref = "protobuf-kotlin" } -protobuf-protoc = { group = "com.google.protobuf", name ="protoc", version.ref = "protobuf-kotlin" } +protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf-kotlin" } retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } retrofit2-kotlin-serialization = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "retrofit" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } @@ -192,4 +192,5 @@ kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization" } protobuf = { id = "com.google.protobuf" } android-library = { id = "com.android.library" } - +google-services = { id = "com.google.gms.google-services" } +firebase-crashlytics = { id = "com.google.firebase.crashlytics" }