I am trying to migrate my gradle project from groovy to kotlin dsl.
Hopefully theres some one can help me.
So, my project used modularization and this is how my project structure looks like
root
├── shared_build.gradle
├── shared_build_core.gradle
├── shared_build_feature.gradle
├── shared_build_sub_feature.gradle
├── build.gradle
│
├── app
│ ├── build.gradle.kts
│
├── core
│ │
│ ├── core-data
│ │ ├── build.gradle
│ │
│ ├── core-navigation
│ │ ├── build.gradle
│ │
│ ├── core-resource
│ │ ├── build.gradle
│ │
│ ├── core-analytics
│ │ ├── build.gradle
│ │
│ └── core-util
│ ├── build.gradle
│
│
├── features
│ ├── feature-auth
│ │ ├── build.gradle
│ │
│ ├── feature-home
│ │ ├── build.gradle
│ └── ...
│
└── settings.gradle
yap its complicated. this is code legacy from my senior (he got resign). i tried to breakdown one by one.
there is 3 type of module :
- core module
- feature module
- sub-feature module
for achieve the clean code on gradle every core, feature, and sub-feature he make a share gradle which :
- share_build.gradle : top level share gradle
- share_build_core.gradle : for core module (apply from share_build.gradle)
- share_build_feature.gradle : for feature module (apply from share_build.gradle)
- share_build_sub_feature.gradle : for sub feature module (apply from share_build.gradle)
here is step i did for migrate before using version contorl i used the versions.gradle file like this.
ext.versions = [
//region Release
code : 68,
name : "2.15.0",
//release version 60
schemaDatabaseVersion : 62,
schemaDatabaseBeforeVersion: 61,
//endregion
//region SDK
compileSdkVersion : 33,
minSdkVersion : 27,
targetSdkVersion : 33,
//endregion
//region Plugin
agp : '8.5.0',
crashlytics : '2.5.2',
google_services : '4.3.14',
kotlin : '1.8.0',
navigation_safe_args : '2.5.0',
firebase_perf_plugin : '1.4.1',
]
ext.plugin = [
agp : "com.android.tools.build:gradle:$versions.agp",
crashlytics : "com.google.firebase:firebase-crashlytics-gradle:$versions.crashlytics",
google_services : "com.google.gms:google-services:$versions.google_services",
kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin",
navigation_safe_args: "androidx.navigation:navigation-safe-args-gradle-plugin:$versions.navigation_safe_args",
firebase_perf : "com.google.firebase:perf-plugin:$versions.firebase_perf_plugin",
oneSignal : "gradle.plugin.com.onesignal:onesignal-gradle-plugin:$versions.oneSignal"
]
ext.deps = [
//region Common
stdlib : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin",
coroutines : [
"org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.coroutine",
"org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutine"
],
material : "com.google.android.material:material:$versions.material",
koin : [
"io.insert-koin:koin-android:$versions.koin",
"io.insert-koin:koin-android-compat:$versions.koin",
"io.insert-koin:koin-androidx-workmanager:$versions.koin",
"io.insert-koin:koin-androidx-navigation:$versions.koin"
],
jdk_lib : "com.android.tools:desugar_jdk_libs:$versions.jdk_lib",
kotlin_reflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin_reflect",
]
i create a version control (libs.versions.toml)
libs.versions.toml
its just a few dependencies i used.
[versions]
#plugins
agp = "8.5.0"
kotlin = "1.8.0"
#dependencies
dexguard = "9.8.0"
kotlinGradle = "1.8.0"
navigationSafeArgs = "2.5.3"
googleServices = "4.3.15"
firebasePlugin = "2.9.5"
firebasePerfPlugin = "1.4.1"
#Koin
koin = "3.2.2"
# JetPack
lifecycle = "2.6.0-alpha04"
appCompat = "1.7.0-alpha01"
core = "1.10.0-alpha01"
# Firebase
firebaseBom = "31.4.0"
firebaseConfig = "21.1.2"
# Extras
debugBanner = "1.0.4"
leakCanary = "2.10"
logger = "2.2.0"
localeHelper = "1.1.4"
dateTimeUtils = "v0.2.1"
lottie = "5.2.0"
# Encryption and Security
sqlcipher = "4.5.3"
# Material
material = "1.8.0-rc01"
#Common Dependencies
stdLib = "1.3.41"
kotlinReflect = "1.4.0"
jdkLib = "1.0.9"
#Testing
junit = "4.13-beta-3"
truth = "1.0-rc2"
robolectric = "4.9.2"
hamcrest = "2.1"
test_core = "1.4.0-alpha05"
test_runner = "1.4.0-alpha05"
test_rules = "1.4.0-alpha05"
test_espresso = "3.3.0-alpha01"
test_ext_junit_ktx = "1.1.3-alpha05"
test_ext_truth = "1.3.0-alpha01"
test_fragment = "1.2.0-alpha01"
mockk = "1.13.3"
test_livedata = "2.1.0"
#Security
securityCrypto = "1.1.0-alpha02"
securePreferences = "0.1.7"
#Gson
gson = "2.10.1"
[libraries]
#common dependencies
kotlinStdLib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "stdLib" }
kotlinReflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlinReflect" }
jdkLib = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "jdkLib" }
#dependencies
gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" }
dexguard = { group = "com.guardsquare", name = "dexguard-gradle-plugin", version.ref = "dexguard" }
kotlinGradle = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlinGradle" }
navigationSafeArgs = { group = "androidx.navigation", name = "navigation-safe-args-gradle-plugin", version.ref = "navigationSafeArgs" }
googleServices = { group = "com.google.gms", name = "google-services", version.ref = "googleServices" }
firebasePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebasePlugin" }
firebasePrerfPlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" }
# koin
koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" }
koin-android-compat = { group = "io.insert-koin", name = "koin-android-compat", version.ref = "koin" }
koin-androidx-workmanager = { group = "io.insert-koin", name = "koin-androidx-workmanager", version.ref = "koin" }
koin-androidx-navigation = { group = "io.insert-koin", name = "koin-androidx-navigation", version.ref = "koin" }
# JetPack
lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycle" }
lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "lifecycle" }
lifecycle-common-java8 = { group = "androidx.lifecycle", name = "lifecycle-common-java8", version.ref = "lifecycle" }
lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "lifecycle" }
lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "lifecycle" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appCompat" }
appcompat-resources = { group = "androidx.appcompat", name = "appcompat-resources", version.ref = "appCompat" }
core = { group = "androidx.core", name = "core-ktx", version = "core" }
# Firebase
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
firebase-analytics-ktx = { group = "com.google.firebase", name = "firebase-analytics-ktx" }
firebase-crashlytics-ktx = { group = "com.google.firebase", name = "firebase-crashlytics-ktx" }
firebase-perf = { group = "com.google.firebase", name = "firebase-perf" }
firebase-config-ktx = { group = "com.google.firebase", name = "firebase-config-ktx", version.ref = "firebaseConfig" }
firebase-messaging-ktx = { group = "com.google.firebase", name = "firebase-messaging-ktx" }
# Extras
debugBanner = { group = "com.github.armcha", name = "DebugBanner", version.ref = "debugBanner" }
leakCanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakCanary" }
logger = { group = "com.orhanobut", name = "logger", version.ref = "logger" }
localeHelper = { group = "com.zeugmasolutions.localehelper", name = "locale-helper-android", version.ref = "localeHelper" }
dateTimeUtils = { group = "com.github.fadhyyusuf", name = "BithealthDateTimeUtils", version.ref = "dateTimeUtils" }
lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "lottie" }
# Encryption and Security
sqlcipher = { group = "net.zetetic", name = "android-database-sqlcipher", version.ref = "sqlcipher" }
# Material
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
#Testing
junit = { group = "junit", name = "junit", version.ref = "junit" }
truth = { group = "com.google.truth", name = "truth", version.ref = "truth" }
robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" }
hamcrest = { group = "org.hamcrest", name = "hamcrest", version.ref = "hamcrest" }
test_core = { group = "androidx.test", name = "core-ktx", version.ref = "test_core" }
test_runner = { group = "androidx.test", name = "runner", version.ref = "test_runner" }
test_rules = { group = "androidx.test", name = "rules", version.ref = "test_rules" }
test_espresso_contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "test_espresso" }
test_espresso_intents = { group = "androidx.test.espresso", name = "espresso-intents", version.ref = "test_espresso" }
test_espresso_accessibility = { group = "androidx.test.espresso", name = "espresso-accessibility", version.ref = "test_espresso" }
test_espresso_remote = { group = "androidx.test.espresso", name = "espresso-remote", version.ref = "test_espresso" }
test_espresso_idling_concurrent = { group = "androidx.test.espresso.idling", name = "idling-concurrent", version.ref = "test_espresso" }
test_espresso_idling_net = { group = "androidx.test.espresso.idling", name = "idling-net", version.ref = "test_espresso" }
test_ext_junit_ktx = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "test_ext_junit_ktx" }
test_ext_truth = { group = "androidx.test.ext", name = "truth", version.ref = "test_ext_truth" }
test_fragment = { group = "androidx.fragment", name = "fragment-testing", version.ref = "test_fragment" }
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
test_livedata = { group = "androidx.arch.core", name = "core-testing", version.ref = "test_livedata" }
#Security
securityCrypto = { group = "androidx.security", name = "security-crypto", version.ref = "securityCrypto" }
securePreferences = { group = "com.scottyab", name = "secure-preferences-lib", version.ref = "securePreferences" }
#Gson
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
googleGms = { id = "com.google.gms.google-services", version.ref = "googleServices" }
firebaseCrashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebasePlugin" }
firebasePerf = { id = "com.google.firebase.firebase-perf", version.ref = "firebasePerfPlugin" }
benManesVersions = { id = "com.github.ben-manes.versions", version = "0.42.0" }
detekt = { id = "io.gitlab.arturbosch.detekt", version = "1.23.3" }
sonarqube = { id = "org.sonarqube", version = "4.2.1.3168" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version = "1.8.0" }
next is i success to migrate my build.gradle level project and app
heres the gradle :
build.gradle level project
buildscript {
dependencies {
classpath(libs.dexguard)
classpath(libs.kotlinGradle)
classpath(libs.gradlePlugin)
classpath(libs.navigationSafeArgs)
classpath(libs.googleServices)
classpath(libs.firebasePlugin)
classpath(libs.firebasePrerfPlugin)
}
}
plugins {
alias(libs.plugins.benManesVersions)
alias(libs.plugins.detekt)
alias(libs.plugins.sonarqube)
alias(libs.plugins.kotlinAndroid) apply false
}
subprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
kotlinOptions {
jvmTarget = "1.8"
allWarningsAsErrors = false
}
}
}
sonar {
properties {
property("sonar.projectKey", "xxxxxxxxxx")
property("sonar.projectName", "xxxxxxxxx")
}
}
detekt {
allRules = false
config.setFrom("$projectDir/detekt.yml")
reports {
xml.required.set(true)
txt.required.set(true)
}
}
tasks.withType<io.gitlab.arturbosch.detekt.Detekt> {
jvmTarget = "1.8"
}
and this is build.gradle level app
build.gradle level app
import java.util.Properties
import java.io.FileInputStream
plugins {
id("com.android.application")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
id("com.google.firebase.firebase-perf")
id("dexguard")
}
apply(from = "../shared_build.gradle")
val keystorePropertiesFile = rootProject.file("keys/keystore.properties")
val keystoreProperties = Properties().apply {
load(FileInputStream(keystorePropertiesFile))
}
android {
defaultConfig {
applicationId = "com.example.xxx"
javaCompileOptions {
annotationProcessorOptions {
arguments(
mapOf(
"room.schemaLocation" to "$projectDir/schemas",
"room.incremental" to "true",
"room.expandProjection" to "true"
)
)
}
}
}
signingConfigs {
create("release") {
keyAlias = keystoreProperties["releaseKeyAlias"] as String
keyPassword = keystoreProperties["releaseKeyPassword"] as String
storeFile = file(keystoreProperties["releaseStoreFile"] as String)
storePassword = keystoreProperties["releaseStorePassword"] as String
}
create("preProd") {
keyAlias = keystoreProperties["preprodKeyAlias"] as String
keyPassword = keystoreProperties["preprodKeyPassword"] as String
storeFile = file(keystoreProperties["preprodStoreFile"] as String)
storePassword = keystoreProperties["preprodStorePassword"] as String
}
create("stagingProd") {
keyAlias = keystoreProperties["stagingProdKeyAlias"] as String
keyPassword = keystoreProperties["stagingProdKeyPassword"] as String
storeFile = file(keystoreProperties["stagingProdStoreFile"] as String)
storePassword = keystoreProperties["stagingProdStorePassword"] as String
}
create("staging") {
keyAlias = keystoreProperties["stagingKeyAlias"] as String
keyPassword = keystoreProperties["stagingKeyPassword"] as String
storeFile = file(keystoreProperties["stagingStoreFile"] as String)
storePassword = keystoreProperties["stagingStorePassword"] as String
}
getByName("debug") {
keyAlias = keystoreProperties["debugKeyAlias"] as String
keyPassword = keystoreProperties["debugKeyPassword"] as String
storeFile = file(keystoreProperties["debugStoreFile"] as String)
storePassword = keystoreProperties["debugStorePassword"] as String
}
}
buildTypes {
getByName("release") {
isCrunchPngs = false
isShrinkResources = false
isMinifyEnabled = false
isDebuggable = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release")
}
create("preProd") {
isCrunchPngs = false
isShrinkResources = false
isMinifyEnabled = false
isDebuggable = true
applicationIdSuffix = ".preProd"
versionNameSuffix = "-preProd"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("preProd")
}
create("stagingProd") {
initWith(buildTypes.getByName("debug"))
isCrunchPngs = false
isShrinkResources = false
isMinifyEnabled = false
isDebuggable = true
applicationIdSuffix = ".stagingProd"
versionNameSuffix = "-stagingProd"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("stagingProd")
}
create("staging") {
initWith(buildTypes.getByName("debug"))
isCrunchPngs = false
isShrinkResources = false
isMinifyEnabled = false
isDebuggable = true
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("staging")
}
getByName("debug") {
ext["alwaysUpdateBuildId"] = false
isShrinkResources = false
isMinifyEnabled = false
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
signingConfig = signingConfigs.getByName("debug")
// configure<FirebasePerformanceExtension> {
// setInstrumentationEnabled(false)
// }
}
}
packagingOptions {
resources {
excludes += "META-INF/*.kotlin_module"
}
}
namespace = "com.example.xxx"
// lint {
// isAbortOnError = false
// isCheckReleaseBuilds = false
// isWarningsAsErrors = false
// }
}
dexguard {
path = "D:\\DexGuard\\DexGuard-9.8.0\\DexGuard-9.8.0"
license = "D:\\DexGuard\\dexguard-license.txt"
configurations {
register("release") {
defaultConfiguration("dexguard-release.pro")
configurations("dexguard-project.txt")
}
}
}
dependencies {
// region Module
implementation(project(":feature-home"))
implementation(project(":feature-auth"))
implementation(project(":core-data"))
implementation(project(":core-navigation"))
implementation(project(":core-resource"))
implementation(project(":core-analytics"))
implementation(project(":core-util"))
implementation(project(":core-integration"))
// endregion
// region Common
implementation(libs.koin.android)
implementation(libs.koin.android.compat)
implementation(libs.koin.androidx.workmanager)
implementation(libs.koin.androidx.navigation)
// endregion
// region JetPack
implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.lifecycle.livedata.ktx)
implementation(libs.lifecycle.viewmodel.savedstate)
implementation(libs.lifecycle.common.java8)
implementation(libs.lifecycle.service)
implementation(libs.lifecycle.process)
// endregion
// region Firebase
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics.ktx)
implementation(libs.firebase.crashlytics.ktx)
implementation(libs.firebase.perf)
implementation(libs.firebase.config.ktx)
implementation(libs.firebase.messaging.ktx)
// endregion
// region Extras
implementation(libs.debugBanner)
debugImplementation(libs.leakCanary)
implementation(libs.logger)
implementation(libs.localeHelper)
// endregion
// region encryption and security
implementation(libs.sqlcipher)
// endregion
implementation(libs.material)
// implementation("com.google.firebase:firebase-crashlytics-ndk")
}
and heres the issue. i cant refactor all the shared gradle even i tried to change the module i got stuck.
ill show you the share gradle file before i refactor it.
share_build.gradle
apply plugin: 'kotlin-android'
//apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion versions.compileSdkVersion
defaultConfig {
minSdkVersion versions.minSdkVersion
targetSdkVersion versions.targetSdkVersion
versionCode versions.code
versionName versions.name
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dexOptions {
javaMaxHeapSize "4g"
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
//region Common
implementation deps.stdlib
implementation deps.kotlin_reflect
coreLibraryDesugaring deps.jdk_lib
//endregion
//region JetPack
implementation deps.appcompat
//endregion
//region Bithealth
implementation deps.date_time_utils
//endregion
//region Extras
implementation deps.logger
implementation deps.timber
implementation deps.lottie
//endregion
//region Local Testing
testImplementation deps.test_core
testImplementation deps.test_runner
testImplementation deps.test_rules
testImplementation deps.test_junit_ktx
testImplementation deps.robolectric
testImplementation deps.mockk
testImplementation deps.test_livedata
testImplementation deps.test_coroutine
//endregion
//region Instrumentation Testing
androidTestImplementation deps.test_core
androidTestImplementation deps.test_runner
androidTestImplementation deps.test_rules
androidTestImplementation deps.test_junit_ktx
androidTestImplementation deps.test_livedata
//endregion
//region Encryption
implementation deps.securityCrypto
implementation deps.securePreferences
//endregion
//region Gson
implementation deps.gson
//endregion
}
share_build_core.gradle
apply plugin: 'com.android.library'
apply from: '../shared_build.gradle'
android {
defaultConfig {
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
buildConfigField("String", "VERSION_NAME", "\"${versions.name}\"")
buildConfigField("String", "VERSION_CODE", "\"${versions.code}\"")
}
preProd {
buildConfigField("String", "VERSION_NAME", "\"${versions.name}\"")
buildConfigField("String", "VERSION_CODE", "\"${versions.code}\"")
}
stagingProd {
matchingFallbacks = ['release']
buildConfigField("String", "VERSION_NAME", "\"${versions.name}\"")
buildConfigField("String", "VERSION_CODE", "\"${versions.code}\"")
}
staging {
matchingFallbacks = ['release']
buildConfigField("String", "VERSION_NAME", "\"${versions.name}\"")
buildConfigField("String", "VERSION_CODE", "\"${versions.code}\"")
}
debug {
buildConfigField("String", "VERSION_NAME", "\"${versions.name}\"")
buildConfigField("String", "VERSION_CODE", "\"${versions.code}\"")
}
}
}
and some gradle from core module
apply from: '../shared_build_core.gradle'
android {
namespace 'com.example.xxx.core.analytics'
}
dependencies {
//region Module
implementation project(':core-data')
implementation project(':core-integration')
//endregion
//region Common
implementation deps.koin
//endregion
//region JetPack
implementation deps.core
//endregion
//region Firebase
implementation platform(deps.firebase)
implementation deps.firebase_analytics
implementation deps.firebase_crashlytics
//endregion
}
and here is the issue.
- i cant access my toml file at share gradle and gradle core module
- i get this error e:
file:///D:/project/shared_build.gradle.kts:7:1: Unresolved reference: android
Sorry for the long explanation from me. Thankyou.