I have and Android module which contains a Gradle JavaExec task. When running the JavaExec task, I would like it to use the classpath of the module.
The JavaExec task executes a Kotlin main function which uses some 3rd party library (kotlinpoet). But when running the Gradle task, I'm getting a java.lang.ClassNotFoundException due to kotlinpoet library not being included in the classpath.
I've found similar issues in StackOverflow, and tried many variants for the classpath parameter in the myTask, but nothing that worked.
Here's is the build.gradle file:
plugins {
id 'com.android.library'
id 'kotlin-android'
}
apply plugin: 'kotlinx-serialization'
android {
compileSdkVersion 30
defaultConfig {
...
}
buildTypes {
...
}
compileOptions {
...
}
kotlinOptions {
jvmTarget = '1.8'
}
}
task myTask(type: JavaExec) {
classpath += (files('build/tmp/kotlin-classes/debug', "${android.sdkDirectory}/tools/lib/kotlin-stdlib-1.1.3-2.jar", getBuildDir().toString() + "/intermediates/classes/debug"))
main = 'com.foo.app.home.parser.MainKt'
}
tasks.named('build') { dependsOn('configGeneratorTask') }
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.core:core-ktx:$androidx_core_ktx"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlinx_serialization_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version"
implementation 'com.squareup:kotlinpoet:1.10.2'
}
You can get the classpath from each variant. This should do the trick:
afterEvaluate { // needed to make sure all android setup is available
task myTask(type: JavaExec) {
// you probably don't even need to set all these paths manually anymore
classpath += files(
'build/tmp/kotlin-classes/debug',
"${android.sdkDirectory}/tools/lib/kotlin-stdlib-1.1.3-2.jar",
getBuildDir().toString() + "/intermediates/classes/debug"
)
android.applicationVariants.each { variant -> // or libraryVariants
// add each variant's compiler classpath onto this classpath
classpath += variant.javaCompileProvider.get().classpath
}
// uncomment the line below if you need the android.jar etc
// classpath += files(android.bootClasspath)
// setting main directly is now deprecated. Set it like this:
mainClass.set('com.foo.app.home.parser.MainKt')
}
}
Also see this answer here: https://stackoverflow.com/a/37268008/3968618
Related
I am using this project to start a gradle plugin development : https://github.com/int128/gradle-plugin-starter
In this project, there are two kinds of tests :
Unit test using spock
Acceptance tests using gradle test kit
My plugin aims to configure android plugin. It is for internal use. We have a lot of projects that are configured in a same way so I want to use the same code base to do that.
Let's say that my plugin code is as follow :
class CopperPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
if(!project.plugins.hasPlugin("com.android.application") && !project.plugins.hasPlugin("com.android.library")){
throw new GradleScriptException("Android plugin needs to be applied first", new ClassNotFoundException())
}
}
}
I don't know how to make acceptance test working !!! Error is :
* What went wrong:
A problem occurred evaluating root project 'fixture-42'.
Plugin with id 'fr.coppernic.android' not found.
Acceptance test code is
#Unroll
def 'acceptance test should pass on Gradle #gradleVersion'() {
given:
def runner = GradleRunner.create()
.withProjectDir(new File("fixture-${gradleVersion.replace(".","")}"))
.withArguments('test')
.withPluginClasspath()
.withGradleVersion(gradleVersion)
when:
runner.build()
then:
noExceptionThrown()
where:
gradleVersion << ['4.2', '3.5']
}
acceptance test build.gradle
plugins {
id 'groovy'
id 'java-gradle-plugin'
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
repositories {
jcenter()
}
dependencies {
testCompile('org.spockframework:spock-core:1.1-groovy-2.4') {
exclude module: 'groovy-all'
}
}
gradlePlugin {
pluginSourceSet parent.sourceSets.main
}
build.gradle from fixture-35 folder
buildscript {
repositories {
jcenter()
maven { url 'http://arti-01:8081/artifactory/plugins-release' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply plugin:'com.android.application'
apply plugin:'fr.coppernic.android'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
}
task test << {
assert project.plugins.hasPlugin('fr.coppernic.android')
}
build.gradle from fixture-42 folder
buildscript {
repositories {
google()
jcenter()
maven { url 'http://arti-01:8081/artifactory/plugins-release' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply plugin: 'com.android.application'
apply plugin: 'fr.coppernic.android'
task test << {
assert project.plugins.hasPlugin('fr.coppernic.android')
}
GradleTestKit only looks in the plugins DSL definition. You are applying your plugin through the apply plugin: syntax which wouldn't work.
I imported the sample app in Android Studio under the location section. I then proceeded to update most of the dependancies. I then attempted to add Firebase and that's when things went south. The module build.gradle is below.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
}
}
apply plugin: 'com.android.application'
repositories {
jcenter()
}
dependencies {
compile 'com.google.android.gms:play-services-location:10.0.1'
compile 'com.google.android.gms:play-services-maps:10.0.1'
compile 'com.github.bumptech.glide:glide:3.6.1'
compile 'com.google.maps.android:android-maps-utils:0.4.4'
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.android.support:design:25.0.1'
compile 'com.google.android.gms:play-services-wearable:10.0.1'
compile 'com.android.support:support-v13:25.0.1'
compile project(':Shared')
wearApp project(':Wearable')
}
// The sample build uses multiple directories to
// keep boilerplate and common code separate from
// the main sample code.
List<String> dirs = [
'main', // main sample code; look here for the interesting stuff.
'common', // components that are reused by multiple samples
'template'] // boilerplate code that is generated by the sample template process
android {
compileSdkVersion 25
buildToolsVersion '24.0.2'
defaultConfig {
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
sourceSets {
main {
dirs.each { dir ->
java.srcDirs "src/${dir}/java"
res.srcDirs "src/${dir}/res"
}
}
androidTest.setRoot('tests')
androidTest.java.srcDirs = ['tests/src']
}
productFlavors {
}
}
apply plugin: 'com.google.gms.google-services'
The root build.gradle is below.
buildscript {
// ...
dependencies {
// ...
classpath 'com.google.gms:google-services:3.0.0'
}
}
And the error I receive is :
Error:Could not find com.google.gms:google-services:3.0.0.
Searched in the following locations:
file:/C:/Android/Android Studio/gradle/m2repository/com/google/gms/google-services/3.0.0/google-services-3.0.0.pom
file:/C:/Android/Android Studio/gradle/m2repository/com/google/gms/google-services/3.0.0/google-services-3.0.0.jar
Required by:
:ToledoZoo:unspecified
Using the latest SDK, and all. Added the google.json file to the app directory as well. I am sure it is something small I am missing, but yet... still missing it!
The module build.gradle is below
app/ is a module, and the buildscript block should not be within that.
The app build.gradle is below.
If by this, you mean build.gradle in the root of the project, then it is that file where you add the classpath of the play services.
Refer. https://firebase.google.com/docs/android/setup#add_the_sdk
Note, when the documentation says
buildscript {
// ...
dependencies {
// ...
classpath 'com.google.gms:google-services:3.0.0'
}
You do not literally copy the // ... pieces. It means "leave what is there already".
If you have a single module Gradle project, then that might make sense looking at your question, and so you need to have
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'com.google.gms:google-services:3.0.0'
}
}
apply plugin: 'com.android.application'
// rest of gradle file
I'm not a Gradle expert. That said, the layout of your build.gradle files is unconventional. Typically, in the module file, the dependencies block is after the android block. Examples of build files are in the Firebase sample project. Take a look at this sample project build file and this sample module build file.
I have just migrated my project to gradle-experimental:0.4.0 to use JNI. I have followed the instructions here
The project consists of a library and an application. I cannot get round this error (tried the usual clean and invalidate cache/restart):
Could not determine the dependencies of task ':myLibrary:transformClassesAndResourcesWithProguardForRelease'
The library build fine but this error appears when I build the app module. Here are my modified build.gradle scripts:
Project:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle-experimental:0.4.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
Library (build OK):
apply plugin: 'com.android.model.library'
model
{
android {
buildToolsVersion="23.0.1"
defaultConfig.with {
minSdkVersion.apiLevel=16
targetSdkVersion.apiLevel=16
testInstrumentationRunner="android.test.InstrumentationTestRunner"
}
}
android.buildTypes {
release {
minifyEnabled=true
proguardFiles.add(file('proguard.cfg'))
}
}
}
App (this build fails):
apply plugin: 'com.android.model.application'
dependencies {
compile files('libs/GoogleAdMobAdsSdk-4.1.1.jar')
compile project(':myLibrary')
}
model
{
android
{
compileSdkVersion='Google Inc.:Google APIs:16'
buildToolsVersion="23.0.1"
defaultConfig.with {
applicationId="my.app.ID"
minSdkVersion.apiLevel=16
targetSdkVersion.apiLevel=16
}
}
android.buildTypes {
release {
minifyEnabled=true
proguardFiles.add(file('proguard.cfg'))
}
}
}
Has anyone seen this error when moving to gradle-experimental?
Ok so removing the proguard line from the library build file fixed this:
--proguardFiles.add(file('proguard.cfg'))
I have a project and migrating to gradle dependency, but I find myself with an issue trying to setup dagger with gradle, the first time I compile it work perfectly (or if I clean) but if I try it twice then it gives me error like:
Error:(13, 14) error: duplicate class: com.myapp.android.application.InjectingApplication$InjectingApplicationModule$$ModuleAdapter
I try using android-apt plugin and configured as in the documentation but I still get the same error (https://bitbucket.org/hvisser/android-apt/overview)
I also try using provided dependency instead like in this tutorial (https://github.com/frankdu/android-gradle-dagger-tutorial) of compile but no luck so far.
Do you have any ideas how to configure dagger and gradle?
EDIT
My build.gradle looks like this
apply plugin: 'android'
apply plugin: 'android-apt'
android {
compileSdkVersion 19
buildToolsVersion "19.0.2"
defaultConfig {
minSdkVersion 9
targetSdkVersion 19
packageName "com.myapp.android"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile project(':volley')
apt 'com.squareup.dagger:dagger-compiler:1.2.0'
compile 'com.squareup.dagger:dagger:1.2.0'
}
And my top level build.gradle look like this
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.2'
}
}
allprojects {
repositories {
mavenCentral()
}
}
EDIT#2:
I tried with provided again as #Marco suggested no luck, I don't know if there is a library or a version of gradle that could be causing this problem, I'm currently using 1.10. On the bright side I did find a way to make it work, but I would love to do it by just adding the provided statement. The way I did it is the old way:
Define apt configuration
configurations {
apt
}
add Dagger compiler lib
apt 'com.squareup.dagger:dagger-compiler:1.2.0'
And implement the this hook to applicationVariant which as far as I know android-apt does something similar. Does this make sense? why?
def getSourceSetName(variant) {
return new File(variant.dirName).getName();
}
android.applicationVariants.each { variant ->
def aptOutputDir = project.file("build/source/apt")
def aptOutput = new File(aptOutputDir, variant.dirName)
android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()
variant.javaCompile.options.compilerArgs += [
'-processorpath', configurations.apt.getAsPath(),
'-s', aptOutput
]
variant.javaCompile.source = variant.javaCompile.source.filter { p ->
return !p.getPath().startsWith(aptOutputDir.getPath())
}
variant.javaCompile.doFirst {
aptOutput.mkdirs()
}
}
I am using dagger in this sample Volley Examples. I'm not experiencing any problems with dagger and I'm including the compiler using:
provided 'com.squareup.dagger:dagger-compiler:1.2.1'
It is work for me.
Step 1:
Add this code to you build.gradle
provided 'com.squareup.dagger:dagger-compiler:1.2.2'
Step 2:
Add source code folder app/gen to you project. So you can add this code to you app/build.gradle (src/main/java is you project core code folder)
sourceSets.main {
java.srcDirs = ['src/main/java', 'gen']
}
Update Gradle plugin to (root/gradle)
classpath 'com.android.tools.build:gradle:2.2.0'
app/gradle
compile 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
I am new to Gradle. Is there some example how to configure properly gradle-android-plugin for scala classes.
this is what I have now.
buildscript {
repositories { mavenCentral() }
dependencies { classpath 'org.gradle.api.plugins:gradle-android-plugin:1.2.1' }
}
apply plugin: 'android'
apply plugin: 'eclipse'
apply plugin: 'scala'
sourceCompatibility = 1.6
version = "1.0.0"
repositories { mavenCentral() }
dependencies {
compile files('/home/pcu/workspace/workspace-android/emoo/libs/android-support-v4.jar')
compile 'org.scala-lang:scala-library:2.9.1'
scalaTools 'org.scala-lang:scala-compiler:2.9.1'
scalaTools 'org.scala-lang:scala-library:2.9.1'
}
task configureDebug << { jar.classifier = "debug" }
task configureRelease << { proguard.enabled = true }
but compilation fails. Scala class is not compiled.
It is actually much simpler with the right plugin:
https://github.com/saturday06/gradle-android-scala-plugin
This worked perfectly fine for me.
You need only about 3 more lines in your gradle configuration and potentially proguard to reduce the apk size.
The setup is well documented on the github page. Everything beyond steps 1-3 is optional.