gradle-lint-plugin icon indicating copy to clipboard operation
gradle-lint-plugin copied to clipboard

Does this work on Android projects?

Open trobalik opened this issue 8 years ago • 22 comments

I created a basic Android project from scratch using Android Studio. I then added compile 'com.google.guava:guava:19.0' to my dependencies, just to give Gradle Lint a test drive. I then added the unused-dependency rule and ran ./gradlew lintGradle, but it reported no violations.

Note that Android projects are multi-module by default, and the artifact produced is an APK file.

trobalik avatar Jun 24 '16 16:06 trobalik

@trobalik Did you add the unused-dependency rule in the root project, or an allprojects block? Rules are configured on a per-project basis, so putting it in allprojects is your best bet.

jkschneider avatar Jun 24 '16 17:06 jkschneider

Here's my root build.gradle file:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'com.netflix.nebula:gradle-lint-plugin:latest.release'
    }
}

allprojects {
    apply plugin: 'nebula.lint'
    gradleLint.rules = ['unused-dependency']//'all-dependency', 'archaic-wrapper', 'duplicate-dependency-class']
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

trobalik avatar Jun 24 '16 17:06 trobalik

and my app/build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.example.gradlelintexample"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'

    compile 'com.google.guava:guava:19.0'
}

trobalik avatar Jun 24 '16 17:06 trobalik

Come find me again if you don't mind! We use ASM to scan class files for type (and therefore dependency) references currently, so we may need an alternate for Android?

jkschneider avatar Jun 24 '16 17:06 jkschneider

I'm sitting behind you right now :) Let's talk after this talk.

trobalik avatar Jun 24 '16 17:06 trobalik

Here's a link to a sample project on Github: https://github.com/trobalik/GradleLintAndroidExample

trobalik avatar Jun 24 '16 18:06 trobalik

I think it's your use of project.convention.getPlugin(JavaPluginConvention). The Android plugin is not based on the Java plugin, so JavaPluginConvention does not get mixed in with Android projects as it does with other JVM projects.

trobalik avatar Jun 26 '16 15:06 trobalik

@trobalik Thanks for the tip. Indeed source sets for Android projects are managed with a completely separate model on the android extension class. The particulars of this implementation make it difficult to associate source sets with their class output destination and classpaths, but I think I've achieved a reasonable approximation with 8f3ec5f1ba1b9f0cd087b3845d5f66f2d62880da.

The rule currently tries to move compile 'com.android.support:appcompat-v7:23.4.0' to the runtime configuration, which doesn't exist in the Android world. What do you think we should do with dependencies like this? Have the rule ignore everything in com.android.support? Are there any other libraries like this that aren't in that group?

jkschneider avatar Jun 27 '16 22:06 jkschneider

Would you prefer me to comment here, or on the commit? First, thanks for working with me on this.

I see an issue with the hard-coded task names. For example: compileReleaseUnitTestJavaWithJavac. That works fine for projects that don't make use of the 'product flavor' concept, but for those that do, it just won't work. E.g., in a project I'm currently working on, I have a task that looks like this: compileUsReleaseUnitTestJavaWithJavac. The 'Us' prefix indicates that this task is for the 'us' flavor of the app.

Our product flavors look like this:

    flavorDimensions "region"
    productFlavors {
        ca {
            applicationId "com.example"
            dimension "region"
        }
        us {
            applicationId "com.example"
            dimension "region"
        }
    }

(note: 'com.example' is a completely arbitrary applicationId that is separate from the project package. It's what identifies the app on Google Play.)

This is because our app works differently in the US and Canada. The 'dimension' attribute is irrelevant for this particular example, but I'm including this here to have an excuse to mention that Android apps can have multiple flavor dimensions. We might, for example, have 'free' and 'paid' flavors alongside our 'region' flavors.

The following code snippet might be of use. It iterates over each application variant ('variant' is the combination of flavor and build type).

android.applicationVariants.all { variant ->
    println variant.name
}

In an app with the two standard build types ('release' and 'debug'), as well as the flavors 'us' and 'ca', this would output:

caDebug
caRelease
usDebug
usRelease

The lower-case first letter is intentional.

I should also note, finally, that 'release' and 'debug' build types are entirely optional -- they're really just suggestions, defined right in the default, wizard-produced build script. Apps may have more or less than those two, and they may be named arbitrarily.

All that said, if you can just get a references to project.android.applicationVariants and loop through the resulting list, that's probably your best bet.

trobalik avatar Jun 28 '16 04:06 trobalik

Excellent explanation @trobalik (and necessary as I was really just guessing)! I'll make that change.

jkschneider avatar Jun 30 '16 17:06 jkschneider

Hey @jkschneider, I know you're busy, but I was just wondering if you've been able to make any progress on this.

trobalik avatar Jul 12 '16 22:07 trobalik

Sorry @trobalik, I haven't, but I'm still itching to get it done soon.

jkschneider avatar Jul 12 '16 22:07 jkschneider

I'd love to help more directly, but I need to get more familiar with your codebase. Maybe I should do that....

trobalik avatar Jul 12 '16 22:07 trobalik

Hello @trobalik @jkschneider . Is there any good news on this topic:) Thanks.

ahmetcj4 avatar Sep 27 '17 13:09 ahmetcj4

I would LOVE if this got fixed for Android. I have no news, though.

autonomousapps avatar Oct 27 '17 00:10 autonomousapps

Any update on this? It still doesn't work for Android...

1951FDG avatar Mar 17 '18 20:03 1951FDG

Any news here?

leobut avatar Aug 10 '18 10:08 leobut

Seems not work. Check my issue https://github.com/nebula-plugins/gradle-lint-plugin/issues/194

ashomokdev avatar Oct 01 '18 11:10 ashomokdev

Years old, but take a look at https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin, a plugin I've authored that at least answers the question of "which of my dependencies are unused"? (among many others)

autonomousapps avatar Jul 08 '20 19:07 autonomousapps

Still finds no violation on 15.x.x and older versions, and on newer 17.x.x version doesn't even compile https://github.com/nebula-plugins/gradle-lint-plugin/issues/342

i think you need to at least state in the documentation that plugin does not support Android projects, so that Android developers don't waste their time

konnovdev avatar Jul 22 '21 09:07 konnovdev

i think you need to at least state in the documentation that plugin does not support Android projects, so that Android developers don't waste their time

THIS. I wasted the entire day trying to get this thing working on my Android project until I found this thread.

4gus71n avatar Mar 21 '24 22:03 4gus71n

@4gus71n PTAL https://github.com/autonomousapps/dependency-analysis-gradle-plugin

autonomousapps avatar Mar 21 '24 23:03 autonomousapps