I'm trying to use dokka on my android project to generate kdoc.
But I have this error when I'm running the script 'modules:app [dokka]' :
Could not determine the dependencies of task ':app:dokka'.
kotlin.KotlinNullPointerException (no error message)
I added the following lines on my gradle files :
Project build.gradle
buildscript {
ext {
dokka_version = '0.9.18'
}
dependencies {
classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:$dokka_version"
}
}
app build.gradle
plugins {
id 'org.jetbrains.dokka-android'
}
dokka {
outputFormat = 'html'
sourceDirs = files('src/main')
outputDirectory = "$buildDir/javadoc"
}
Could not determine the dependencies of task ':app:dokka'.
kotlin.KotlinNullPointerException (no error message)
The issue is that it's a multiplatform project. In the app level gradle file, I'm also applying the org.jetbrains.kotlin.multiplatform plugin. As described in the dokka github release page:
Experimental Kotlin Multiplatform support is scheduled for 0.9.19
Looks like there's no other solution than wait for the next release of dokka.
Edit: There's a workaround described on the kolinlang forum
dokka {
impliedPlatforms = ["common"] // This will force platform tags for all non-common sources e.g. "JVM"
kotlinTasks {
// dokka fails to retrieve sources from MPP-tasks so they must be set empty to avoid exception
// use sourceRoot instead (see below)
[]
}
sourceRoot {
// assuming there is only a single source dir...
path = kotlin.sourceSets.commonMain.kotlin.srcDirs[0]
platforms = ["common"]
}
}
Related
I'm trying to develop a gradle plugin to use it for generating some objects and methods for our api using some scheme.
I have followed some tutorials but they all seem not to work, atleast for me.
Some of these tutorials were:
https://musings.animus.design/kotlin-poet-building-a-gradle-plugin/
https://medium.com/#magicbluepenguin/how-to-create-your-first-custom-gradle-plugin-efc1333d4419
I have not used the buildSrc module because I'm already using it for Kotlin DSL, so I decided to create a new module and create my plugin there.
My plugin's module build.gradle.kts looks like this:
plugins {
id("java-gradle-plugin")
id("kotlin")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath(config.ClassPaths.androidBuildTools)
classpath(config.ClassPaths.kotlinGradlePlugin)
}
}
repositories {
google()
jcenter()
}
dependencies {
implementation(config.ClassPaths.androidBuildTools)
implementation(config.ClassPaths.kotlinGradlePlugin)
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "Generator"
}
}
}
My projects settings.gradle.kts looks like this:
include(":SampleProject", ":scheme-generator")
And in my application module's build.gradle.kts I'm applying this plugin like this:
apply(plugin = "Generator")
The build script stops here with an error: plugin 'Generator' not found
My Generator class looks like this:
class Generator : Plugin<Project> {
override fun apply(target: Project) {
target.android().variants().all { variant ->
// Make a task for each combination of build type and product flavor
val myTask = "myFirstTask${variant.name.capitalize()}"
// Register a simple task as a lambda. We can later move this to its own
// class to make our code cleaner and also add some niceties.
target.tasks.create(myTask){task ->
// Group all our plugin's tasks together
task.group = "MyPluginTasks"
task.doLast {
File("${target.projectDir.path}/myFirstGeneratedFile.txt").apply {
writeText("Hello Gradle!\nPrinted at: ${SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())}")
}
}
}
}
}
}
The android and variants methods are declared in a utils file, they look like this:
object GeneratorUtils {
fun Project.android(): BaseExtension {
val android = project.extensions.findByType(BaseExtension::class.java)
if (android != null) {
return android
} else {
throw GradleException("Project $name is not an Android project")
}
}
fun BaseExtension.variants(): DomainObjectSet<out BaseVariant> {
return when (this) {
is AppExtension -> {
applicationVariants
}
is LibraryExtension -> {
libraryVariants
}
else -> throw GradleException("Unsupported BaseExtension type!")
}
}
}
I have tried many things, but I seem not to get this right.
EDIT:
Using the buildSrc module for my plugin works totally fine, the plugin is applied and the gradle tasks are visible. However, buildSrc is reserved for other purposes, and we would like our plugin to be in a separate module, so we will be able to use it in other projects.
EDIT 13/04/2021
I have managed to see the tasks that are added by my plugin in my app tasks list by including this module as a composite build.
My settings.gradle now looks like this:
pluginManagement {
includeBuild("generator")
}
include(":SampleProject")
build.gradle of my plugin looks like this:
apply plugin: 'java-gradle-plugin' // Allows us to create and configure custom plugins
apply plugin: 'kotlin' //Needed as we'll write our plugin in Kotlin
buildscript {
ext {
kotlin_version = '1.4.31'
gradle_version = '4.1.2'
}
repositories {
google()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.android.tools.build:gradle:$gradle_version"
}
}
repositories {
google()
jcenter()
}
dependencies {
// Android gradle plugin will allow us to access Android specific features
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "com.example.Generator"
}
}
}
And my generator class now looks like this:
class Generator : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("generationTask") { task ->
task.apply {
group = "generation"
actions.add(Action {
print("Hello from generation task!")
})
}
}
}
}
I can see generationTask in my tasks list and I can execute it normally. It prints the text without any problems.
The problem now is to include com.android.tools.build:gradle:4.1.2 in my dependecies to use it to access build types and flavors and their paths to save my generated code there. When I add it to my dependencies block, gradle fails with this error: Could not find com.android.tools.build:gradle:4.1.2.
How can I solve this problem?
Gradle build goes through specific set of phases, and the Configuration phase comes before the Execution phase. So you cannot use a plugin, which is built in the same build process, because by the time gradle tries to use it on Configuration phase, the plugin has not been built yet.
buildSrc directory is a special one, it's built not as part of the same build process, but in a separate build, before the main build process starts. This feature is called included or composite build. buildSrc is just a pre-defined way to set up a composite build and you can define your own included builds. So to make your plugin visible to the main build, you need to put it into a separate build and include this build into a composite build as described in the doc above. Here is an article describing how to transform a plugin defined in buildSrc into a composite build.
I am trying to generate a KDoc documentation in an Android project. Following are the relevant files for adding this functionality.
build.gradle (root level):
buildscript {
...
ext.dokka_version = "0.10.1"
repositories {
...
maven { url "https://dl.bintray.com/kotlin/kotlin-eap/" }
}
dependencies {
...
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
}
}
...
build.gradle (Module:App)
...
apply plugin: 'org.jetbrains.dokka'
...
dokka {
outputFormat = 'html' // use 'javadoc' to get standard java docs
outputDirectory = "$buildDir/javadoc"
configuration {
includeNonPublic = false
skipEmptyPackages = true
skipDeprecated = true
reportUndocumented = true
jdkVersion = 8
}
}
Later, I am running ./gradlew dokka from the command line. But no output is getting generated. Following is what I get:
> Task :app:dokka
logging: loading modules: [java.se, jdk.accessibility, jdk.attach, jdk.compiler, jdk.dynalink, jdk.httpserver, jdk.jartool, jdk.javadoc, jdk.jconsole, jdk.jdi, jdk.jfr, jdk.jshell, jdk.jsobject, jdk.management, jdk.management.jfr, jdk.net, jdk.scripting.nashorn, jdk.sctp, jdk.security.auth, jdk.security.jgss, jdk.unsupported, jdk.unsupported.desktop, jdk.xml.dom, java.base, java.compiler, java.datatransfer, java.desktop, java.xml, java.instrument, java.logging, java.management, java.management.rmi, java.rmi, java.naming, java.net.http, java.prefs, java.scripting, java.security.jgss, java.security.sasl, java.sql, java.transaction.xa, java.sql.rowset, java.xml.crypto, jdk.internal.jvmstat, jdk.management.agent, jdk.jdwp.agent, jdk.internal.ed, jdk.internal.le, jdk.internal.opt]
No documentation for io.elektrifi.outageplanner.GettingStartedActivity (GettingStartedActivity.kt:9)
No documentation for io.elektrifi.outageplanner.GettingStartedActivity$<init>() (GettingStartedActivity.kt:9)
No documentation for io.elektrifi.outageplanner.GettingStartedActivity$onCreate(android.os.Bundle) (GettingStartedActivity.kt:10)
No documentation for io.elektrifi.outageplanner.LoginActivity (LoginActivity.kt:6)
No documentation for io.elektrifi.outageplanner.LoginActivity$<init>() (LoginActivity.kt:6)
No documentation for io.elektrifi.outageplanner.LoginActivity$onCreate(android.os.Bundle) (LoginActivity.kt:7)
No documentation for io.elektrifi.outageplanner.MainActivity (MainActivity.kt:17)
No documentation for io.elektrifi.outageplanner.MainActivity$<init>() (MainActivity.kt:17)
No documentation for io.elektrifi.outageplanner.MainActivity$onCreate(android.os.Bundle) (MainActivity.kt:18)
No documentation for io.elektrifi.outageplanner.RegisterActivity (RegisterActivity.kt:6)
No documentation for io.elektrifi.outageplanner.RegisterActivity$<init>() (RegisterActivity.kt:6)
No documentation for io.elektrifi.outageplanner.RegisterActivity$onCreate(android.os.Bundle) (RegisterActivity.kt:7)
No documentation for io.elektrifi.outageplanner.SplashScreenActivity (SplashScreenActivity.kt:16)
No documentation for io.elektrifi.outageplanner.SplashScreenActivity$<init>() (SplashScreenActivity.kt:16)
No documentation for io.elektrifi.outageplanner.SplashScreenActivity$onCreate(android.os.Bundle) (SplashScreenActivity.kt:19)
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.1.1/userguide/command_line_interface.html#sec:command_line_warnings
In fact, there is a small demo script in MainActivity. I am not sure why nothing is getting generated. Please let me know whether my configuration is correct. Also, it would be great to have a working configuration.
I am a newbie, so I did not realise it. The above configuration works. The KDoc comments must be above the class or function for which we are documenting. I was starting the commenting with /** and ending with */ at the very top of the Kotlin file (before import and package) and it didn't work.
Suppose that the project dependencies are declared as follows:
dependencies {
implementation 'io.mylib:core:1.0.0-SNAPSHOT'
// ....
}
I would like to have a gradle task that will retrieve the mylib dependency and check the version. If the version of the lib is SNAPSHOT then fail the build.
Something like this:
task checkLibVersion(){
version = getDependencyVersion("io.mylib:core") // <-- how to retrieve version
if(version.endsWith("-SNAPSHOT"){
throw new GradleException("Mylib uses snapshot version")
}
}
This task would be part of the release pipeline and will fail the job if current version of mylib is snapshot.
Does anyone know how to retrieve the version of a particular dependency from a gradle task?
OK, it seems this can be done pretty easy if the version number is extracted into an extension property:
In the build.gradle of the root project:
buildscript {
ext.libVersion = '1.3.21-SNAPHOT'
// ....
}
task checkLibVersion(){
def version = "$libVersion"
if (version.endsWith("-SNAPSHOT")){
throw new GradleException("Mylib uses SNAPSHOT version!")
}
}
tasks.whenTaskAdded { task ->
if (task.name == 'assembleRelease') {
task.dependsOn checkLibVersion()
}
}
How do I set up SpotBugs for Android?
I tried following the official documentation and that of the gradle plugin, but the setup for Android is incomplete and confusing, and didn't work.
I tried the following setup.
build.gradle (project):
buildscript {
repositories {
// ...
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
// ...
classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.4"
}
}
build.gradle (app):
//...
apply plugin: "com.github.spotbugs"
android {
// ...
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
}
}
// ...
spotbugs {
toolVersion = "3.1.3"
ignoreFailures = true
reportsDir = file("$project.buildDir/findbugsReports")
effort = "max"
reportLevel = "high"
}
tasks.withType(com.github.spotbugs.SpotBugsTask) {
// What do I need to do here?
}
I tried running it with ./gradlew spotbugsMain, but the gradle task is missing.
Am I supposed to add the task manually? How do I do that?
Could you show me an example of a minimal working setup for an Android project?
I made some tests on my side and I manage to make it work like this :
1) Move the sourceSets declaration outside the android block. Leave it empty, it's just for the spotbugsMain task generation, it won't impact the global Android build.
android {
// ...
}
sourceSets {
main {
java.srcDirs = []
}
}
2) Keep your spotbugs block and configure the SpotBugsTask tasks like this :
tasks.withType(com.github.spotbugs.SpotBugsTask) {
classes = files("$projectDir.absolutePath/build/intermediates/classes/debug")
source = fileTree('src/main/java')
}
It will generate reports in app/build/findbugsReports
Important :
It only works with the ./gradlew build command, ./gradlew spotbugsMain won't work as the project must be built before
You can fix that adding an assemble dependency :
tasks.withType(com.github.spotbugs.SpotBugsTask) {
dependsOn 'assemble'
classes = files("$projectDir.absolutePath/build/intermediates/classes/debug")
source = fileTree('src/main/java')
}
Following on from ToYonos answer (9 October 2018); Use this for Android Studio 3.4 and above:
project/build.gradle
buildscript {
repositories {
google()
jcenter()
maven {
url 'https:// maven url 1'
}
maven {
url "https://plugins.gradle.org/m2/" // Add this, for SpotBugs
}
}
dependencies {
classpath '...'
// If you're using gradle 6.x, add this to use SpotBugs app version 4.0.2
classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.3.0"
// If you're using gradle 4.x or 5.x, add this to use SpotBugs app version 3.1.2
classpath "com.github.spotbugs:spotbugs-gradle-plugin:2.0.1"
}
}
project/app/build.gradle
apply plugin: 'com.android.application'
apply plugin: '...'
apply plugin: "com.github.spotbugs" // <- Add this
dependencies {
...
}
// This block is only needed for gradle 4/5 only.
// It's for SpotBugs to create a 'spotbugsMain' gradle task.
sourceSets {
main {
java.srcDirs = []
}
}
spotbugs {
ignoreFailures = true
reportsDir = file("$project.buildDir/SpotBugsReports")
effort = "max"
reportLevel = "high"
}
// Note: gradle 4/5 should use "com.github.spotbugs.SpotBugsTask"
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
dependsOn 'assembleDebug'
classes = files("$project.buildDir/intermediates/javac") // Important to use this path
excludeFilter = file("$project/spot-bugs-exclude.xml") // Optional - Explained below
source = fileTree('src/main/java') // Only needed on gradle 4/5
reports {
// Enable HTML report only
html.enabled = true
xml.enabled = false
}
}
You can generate a report for your debug build by running the gradle task:
For gradle 6.x: ./gradlew spotbugsDebug
For gradle 5 or 4: ./gradlew spotbugsMain
It's important to use classes = files("$project.buildDir/intermediates/javac") , otherwise you'll get an error "java.io.IOException: No files to analyze could be opened" -- see Findbugs fails with "java.io.IOException: No files to analyze could be opened"
You'll also need to enable the HTML report and disable XML report, to see a human-readable format.
ignoreFailures = true is optional. When SpotBugs detects a code warning, by default it will end with "BUILD FAILED" + a report file. Setting ignoreFailures = true means the gradle task will end with "BUILD SUCCESSFUL" + a report file.
To exclude some generated classes from the analysis, setup an excludeFilter. For a sample exclude file, check here or here (same as findbugs-exclude.xml)
More information and tutorial here: https://mikedemaso.com/tech/2020-06-10-spotbugs-gradle-plugin-android/
I'm trying to generate .java files from the .proto files I have stored under my SRC folder in Android studio. I put the below code in my gradle file by it doesn't seem to work
apply plugin: 'com.squareup.wire'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.squareup.wire:wire-maven-plugin:2.1.1'
}
}
There is a gradle plugin for wire here: https://github.com/square/wire-gradle-plugin. However, it seems like it's not quite ready for primetime yet. I had some trouble getting it working.
But, here's a way to do it that automates generation of java code from the *.proto files using the wire compiler directly and a simple gradle task. I've provided a snippet below with the modifications to your build.gradle. Change the protoPath and wireGeneratedPath based on your source layout.
def protoPath = 'src/proto'
def wireGeneratedPath = 'build/generated/source/wire'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.squareup.wire:wire-compiler:2.2.0'
}
}
android {
sourceSets {
main {
java {
include wireGeneratedPath
}
}
}
}
dependencies {
compile 'com.squareup.wire:wire-runtime:2.2.0'
// Leave this out if you're not doing integration testing...
androidTestCompile 'com.squareup.wire:wire-runtime:2.2.0'
}
// This handles the protocol buffer generation with wire
task generateWireClasses {
description = 'Generate Java classes from protocol buffer (.proto) schema files for use with squareup\'s wire library'
delete(wireGeneratedPath)
fileTree(dir: protoPath, include: '**/*.proto').each { File file ->
doLast {
javaexec {
main = 'com.squareup.wire.WireCompiler'
classpath = buildscript.configurations.classpath
args = ["--proto_path=${protoPath}", "--java_out=${wireGeneratedPath}", "${file}"]
}
}
}
}
preBuild.dependsOn generateWireClasses
So instead of using a gradle plugin I just ended up using the square wire compiler jar. Here are the steps.
Download compiler-jar-with-dependencies from http://search.maven.org/#artifactdetails%7Ccom.squareup.wire%7Cwire-compiler%7C2.1.1%7Cjar
Put jar file into root directory of android app
Go to the directory and paste this command
java -jar wire-compiler-2.1.1-jar-with-dependencies.jar --proto_path=directory-of-protofile --java_out=app/src/main/java/ name-of-file.proto
Should work. Make sure to replace the directory-of-protofile and name-of-file with whatever you have.