Minimal working SpotBugs setup for Android Studio
Asked Answered
O

2

26

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?

Orangeman answered 4/10, 2018 at 9:52 Comment(3)
If the downvoters would tell me why, I could improve the question.Orangeman
@Orangeman Your question seems perfectly fine to me, and I don't understand why anyone has down voted it. Even more bizarre is that two people have voted to close a question about how to configure SpotBugs for Android as "off topic"!Sonorant
Here is an example: gist.github.com/mik9/fdde79052fef7f03c4325734701a39d7Snowflake
A
12

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')
}
Algoid answered 9/10, 2018 at 10:32 Comment(1)
I give up. I can't get it to work with gradle 6 (plugin v 4.5)Inserted
I
9

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/

Impeditive answered 5/6, 2019 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.