Gradle Kotlin DSL unresolved references defined in buildSrc - android

I'm experimenting with Kotlin DSL but I can't get it to recognize objects I defined in buildSrc. They get resolved by the IDE but when I compile the code it doesn't work.
This is the my project structure:
build.gradle.kts
settings.gradle.kts
+buildSrc
build.gradle.kts
+src
+main
+java
Dependencies.kt
Versions.kt
+module1
build.gradle.kts
+module2
build.gradle.kts
Content of Dependencies.kt:
/**
* To define plugins
*/
object BuildPlugins {
val gradle by lazy { "com.android.tools.build:gradle:${Versions.gradlePlugin}" }
val kotlinGradle by lazy { "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" }
val safeArgs by lazy { "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.safeArgs}" }
}
/**
* To define dependencies
*/
object Deps {
val appCompat by lazy { "androidx.appcompat:appcompat:${Versions.appCompat}" }
val core by lazy { "androidx.core:core-ktx:${Versions.core}" }
val timber by lazy { "com.jakewharton.timber:timber:${Versions.timber}" }
val kotlin by lazy { "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}" }
val material by lazy { "com.google.android.material:material:${Versions.material}" }
val constraintLayout by lazy { "androidx.constraintlayout:constraintlayout:${Versions.constraintLayout}" }
}
Project wide build.gradle.kts (the one which fails first):
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
BuildPlugins.gradle
BuildPlugins.kotlinGradle
BuildPlugins.safeArgs
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
...
I also want to point out that the android { ... } block is not recognized in the modules gradle files but I think that may be because of the failed compilation.

You have Kotlin files under src/main/java. They should be in src/main/kotlin and you will need to include Kotlin build support in the buildSrc Gradle file (maybe you have this, you didn't show what's in buildSrc/build.gradle.kts)
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}

Related

Cannot process test roots and app roots in the same compilation unit Hilt Android

I get this build error:
Cannot process test roots and app roots in the same compilation unit:
When I am trying to write the instrumented test like this:
#HiltAndroidTest
class DataRecognitionRepositoryImplTest {
#get:Rule
var hiltRule = HiltAndroidRule(this)
#Test
fun first() {
}
}
I have also created my own runner like this:
class HiltTestRunner: AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?
): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
And set it like:
testInstrumentationRunner "com.mayurg.helpers.HiltTestRunner"
My root build file:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.40.5"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
I have tried searching a lot but did not find anything useful apart from this: https://dagger.dev/hilt/flags
But I am not sure how/where to use these. Any help is appreciated.
To fix this you need to add this to your build.gradle file:
android {
defaultConfig {
javaCompileOptions.annotationProcessorOptions.arguments['dagger.hilt.disableCrossCompilationRootValidation'] = 'true'
}
}

Project :app declares a dependency from configuration 'implementation' to configuration 'debug' which is not declared in the descriptor for project

I am trying to add a Kotlin Multiplatform Module as part of an Android project I am building. In the library, my top level build.gradle.kts looks like this:
buildscript {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
classpath("com.android.tools.build:gradle:7.1.0")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
Then my app level build.gradle.kts looks like this:
plugins {
kotlin("multiplatform")
id("com.android.library")
}
kotlin {
android()
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "shared"
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val androidMain by getting
val androidTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
}
val iosX64Test by getting
val iosArm64Test by getting
val iosSimulatorArm64Test by getting
val iosTest by creating {
dependsOn(commonTest)
iosX64Test.dependsOn(this)
iosArm64Test.dependsOn(this)
iosSimulatorArm64Test.dependsOn(this)
}
}
}
android {
compileSdk = 31
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 24
targetSdk = 31
}
}
Back in my Android project I am including the file in the settings.gradle like this:
include ':SampleModule'
project(':SampleModule').projectDir = new File(settingsDir, '../SampleModule')
Then in my build.gradle like this:
implementation project(path: ':SampleModule')
Unfortunately though, I keep getting the same frustrating error:
Could not determine the dependencies of task ':app:mergeDebugAssets'.
> Could not resolve all task dependencies for configuration ':app:debugRuntimeClasspath'.
> Could not resolve project :SampleModule.
Required by:
project :app
> Project :app declares a dependency from configuration 'implementation' to configuration 'custombuild' which is not declared in the descriptor for project :SampleModule.
Any idea why this might be happening?

Using Gradle plugin from composite build in root project buildscript

I use Gradle Kotlin DSL and in my project I have separate build-dependencies gradle module which is included in settings.gradle.kts like so:
pluginManagement {
repositories {
google()
jcenter()
gradlePluginPortal()
}
}
includeBuild("build-dependencies")
This module contains empty plugin implementation and Deps object. Its build.gradle.kts below:
repositories {
google()
jcenter()
gradlePluginPortal()
}
plugins {
`kotlin-dsl`
`java-gradle-plugin`
}
gradlePlugin {
plugins.register("com.example.dependencies") {
id = "com.example.dependencies"
implementationClass = "com.example.dependencies.DependenciesPlugin"
}
}
Deps object:
object Deps {
const val buildTools = "com.android.tools.build:gradle:4.1.1"
// more dependencies
}
I want to use this Deps object in all modules by applying the plugin in build.gradle.kts files.
plugins {
id("com.example.dependencies")
}
And it works fine, I can import and use Deps object.
But there is a problem when I want to use it in root projects build.gradle.kts and more precisely in buildscript like so:
buildscript {
repositories {
google()
jcenter()
}
plugins {
id("com.example.dependencies")
}
dependencies {
classpath(com.example.dependencies.Deps.buildTools) // It doesn't work
}
}
Is there any way to use a custom plugin inside buildscript like this or could you suggest something to replace this approach?
I also wonder this. However, I think this is the difference between includeBuild and buildSrc.

How to create a FlavorConfig in BuildSrc?

I'm trying to create a Flavor configuration to avoid boilerplate code in every Module and Library gradle file.
To do so I'm trying to convert Piotr Zawadzki solution (https://medium.com/stepstone-tech/modularizing-your-flavored-android-project-5db75c59fb0d) which uses the groovy with() method combined with a Closure containing the flavor config.
ext.flavorConfig = { // 1
flavorDimensions "pricing"
productFlavors {
free {
dimension "pricing"
ext.myApplicationIdSuffix = '.free' // 2
}
paid {
dimension "pricing"
ext.myApplicationIdSuffix = '.paid'
}
}
productFlavors.all { flavor -> // 3
if (flavor.hasProperty('myApplicationIdSuffix') && isApplicationProject()) {
flavor.applicationIdSuffix = flavor.myApplicationIdSuffix
}
}
}
def isApplicationProject() { // 4
return project.android.class.simpleName.startsWith('BaseAppModuleExtension')
// in AGP 3.1.x with library modules instead of feature modules:
// return project.android instanceof com.android.build.gradle.AppExtension
}
What I'm not finding is the equivalent with() method for the Kotlin DSL or a proper way to translate the Closure.
An equivalent should be apply or run, depending on what's the actual return value of with (which I couldn't figure out for some reason).
I found a solution with KotlinScript, I think it could be done with Groovy too.
First, add gradle-api dependency in your buildSrc/build.gradle.kts file
//buildSrc/build.gradle.kts
val agpVersion = "7.1.1"
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
google()
}
dependencies{
implementation("com.android.tools.build:gradle-api:$agpVersion")
}
Then create a Gradle Plug-In in buildSrc.
//buildSrc/src/main/kotlin/FooPlugin.kt
abstract class FooPlugin : Plugin<Project> {
override fun apply(project: Project) {
val android = project.extensions.getByType(ApplicationExtension::class.java)
android.defaultConfig {
android.productFlavors.create("Bar")
}
}
}
Finally apply FooPlugin to your application's build.gradle.kts
//baz/build.gradle.kts
plugins {
...
}
apply<FooPlugin>()
android{
...
}
dependencies {
...
}

How to reuse parts of Android configuration in Kotlin Gradle DSL for multiple modules?

I have a multi-module Android project & Kotlin Gradle DSL. There is some configuration which has to be repeated in every module and I would like to reuse the code. I would like to reuse for example this code:
android {
sourceSets {
getByName("main").java.srcDirs("src/main/kotlin")
getByName("test").java.srcDirs("src/test/kotlin")
}
}
There are two methods documented in Kotlin DSL samples:
apply(from = "foo.gradle.kts")
and extension functions in buildSrc like this:
fun Project.kotlinProject() {
dependencies {
"compile"(kotlin("stdlib"))
}
}
However both these methods work only for top-level configuration, I can't access Android plugin's stuff. I'm getting errors like Unresolved reference: BaseExtension
At the end I was inspired by SUPERCILEX's code:
allprojects {
val parent = (group as String).split(".").getOrNull(1)
when {
name == "app" -> {
apply(plugin = "com.android.application")
configureAndroidModule()
}
parent == "common-android" -> {
apply(plugin = "com.android.library")
configureAndroidModule()
}
}
}
fun Project.configureAndroidModule() {
configure<BaseExtension> {
sourceSets {
getByName("main").java.srcDirs("src/main/kotlin")
getByName("test").java.srcDirs("src/test/kotlin")
}
}
}​
How about using subprojects block? I have a multi-module Android project and this is how I reuse code in my build scripts.
subprojects {
apply plugin: 'com.android.library'
android {
sourceSets {
getByName("main").java.srcDirs("src/main/kotlin")
getByName("test").java.srcDirs("src/test/kotlin")
}
}
}
Unresolved reference: BaseExtension
As for the above error message, if you want to use android block, you should declare your modules as android application or library by applying plugins like above build script.
If you want the settings to be repeated in only some of the modules, you can use configure block like this:
configure(subprojects - project(':${module_name}')) {
dependencies {
implementation 'com.x.y.z:abc:1.0.0'
}
}
The above block will define the dependency on all modules except the module with the given name.

Categories

Resources