irgaly / android-remove-unused-resources-plugin

A gradle plugin to remove unused android resources by Android Lint results xml file.
https://plugins.gradle.org/plugin/io.github.irgaly.remove-unused-resources
Other
29 stars 1 forks source link
android gradle-plugin

Remove Unused Resources Plugin for Android

A gradle plugin to remove unused android resources by Android Lint results xml file.

This is useful for CI because that is provided by gradle task.

Concepts

Requires

Usage

Apply the plugin to your app module.

app/build.gradle.kts

plugins {
  id("io.github.irgaly.remove-unused-resources") version "2.2.0"
}

Ensure your lint option is correctly set for UnusedResources rule.

app/build.gradle.kts

android {
  ...
  lint {
    // checkGeneratedSources is slow down Android Lint analysing.
    // It is recommended to disable this when you analyse other lint rules.
    checkGeneratedSources = true
    // checkDependencies = true : checkDependencies is true by default
  }
}

othermodule/build.gradle.kts

android {
  ...
  lint {
    // if a module uses code generation, this is required each project.
    checkGeneratedSources = true
  }
}

Run Android Lint, that contains UnusedResources analyser.

% ./gradlew :app:lintDebug

Run clean up task, then unused resources are deleted. There are removeUnusedResources{variant} tasks.

% ./gradlew :app:removeUnusedResourcesDebug

console outputs like:

> Task :app:removeUnusedResourcesDebug
> report from: .../app/src/main/res/values/colors.xml
delete resource element: R.color.black
delete resource element: R.color.unused_color
delete resource element: R.color.unused_color_with_night_theme
...

modified XML exmaple:

Only modifies unused resource tag, preserve others (XML indent, spaces, special reference characters...) as it is.

--- a/sample/src/main/res/values/strings.xml
+++ b/sample/src/main/res/values/strings.xml
@@ -1,7 +1,6 @@
 <!-- header comment -->
 <resources>
     <string name="app_name">Plugin Sample</string>
-    <string name="unused_string">unused</string>
     <string name="empty1" />
     <string name="empty2"></string>
     <string name="character_reference">© = &#169;</string>

Run lint only for UnusedResources rule

This plugin provides simple utility for lint, that overrides lint options.

For example, this command let lint to check only UnusedResources rule.

% ./gradlew :app:lintDebug -Prur.lint.onlyUnusedResources

The -Prur.lint.onlyUnusedResources overrides lint options by settings below:

android {
  lint {
    // These settings are applied automatically by the plugin, when -Prur.lint.onlyUnusedResources is specified,
    // so you don't have to add these settings in build.gradle.kts.
    xmlReport = true // only app project
    checkDependencies = true // only app project
    checkGeneratedSources = true
    checkOnly.clear()
    checkOnly.add("UnusedResources")
    warning.add("UnusedResources")
  }
}

Overrides lintConfig

You can overrides a single lintConfig file for all projects.

% ./gradlew :app:lintDebug -Prur.lint.overrideLintConfig="./lint.unusedresources.xml"

The details of lint.xml format is here .

CI usage example

This is an example for CI usage.

% ./gradlew :app:lintDebug -Prur.lint.onlyUnusedResources
% ./gradlew :app:removeUnusedResourcesDebug

This executes:

Exclude Resources rules

There are options to set exclude resource ID rules or file path rules.

See Gradle configuration syntax section.

Gradle task and options

Gradle tasks:

task description
removeUnusedResources{variant} delete unused resources by {buildDir}/reports/lint-results-{variant}.xml
removeUnusedResources delete unused resources by {buildDir}/reports/lint-results-{default variant}.xml

Gradle properties:

property description example
rur.dryRun only output result, without deletion ./gradlew :app:removeUnusedResourcesDebug -Prur.dryRun
rur.lintResultXml the lint result xml path from rootProject (or full absolute path). this option is only for removeUnusedResources task, it's ignored by removeUnusedResources{variant} task. ./gradlew :app:removeUnusedResources -Prur.lintResultXml="./app/build/reports/lint-results-debug.xml"
rur.lint.onlyUnusedResources override lint option for checkOnly UnusedResources ./gradlew :app:lintDebug -Prur.lint.onlyUnusedResources
rur.lint.overrideLintConfig override lint.lintConfig. the path is relative path from rootProject (or full absolute path) ./gradlew :app:lintDebug -Prur.lint.overrideLintConfig="./lint.unusedresources.xml"

Gradle configuration syntax

Gradle configuration syntax is also available.

app/build.gradle.kts

removeUnusedResources {
  // for dry run
  // default: false
  dryRun = true

  // specify lint result xml directly
  // this option is only for `removeUnusedResources` task, it's ignored by `removeUnusedResources{variant}` task.
  // default: {buildDir}/reports/lint-results-{default variant}.xml)
  lintResultXml = file("$buildDir/reports/lint-results-debug.xml")

  // exclude resource Id list. match rule: entire match
  excludeIds.add("R.color.unused_exclude_color")

  // regular expression exclude resource Id list. match rule: regular expression entire match
  excludeIdPatterns.add("R\\..*exclude_pattern.*")

  // glob expression exclude file.
  // file path is relative path from Project's root directory
  excludeFilePatterns.add("**/values/exclude_colors.xml")
}

The details of glob pattern is documented in JDK FileSystem#getPathMatcher

Note: Other behaviors

Troubleshoots

No matching variant of io.github.irgaly.remove-unused-resources:plugin:... was found.

This error is occurred with running Gradle on JVM 11. Running Gradle on JVM 17 will solve this error.

...
FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':sample'.
> Could not resolve all files for configuration ':sample:classpath'.
   > Could not resolve io.github.irgaly.remove-unused-resources:plugin:1.4.1.
     Required by:
         project :sample > io.github.irgaly.remove-unused-resources:io.github.irgaly.remove-unused-resources.gradle.plugin:1.4.1
      > No matching variant of io.github.irgaly.remove-unused-resources:plugin:1.4.1 was found. The consumer was configured to find a runtime of a library compatible with Java 11, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '7.4' but:
          - Variant 'apiElements' capability io.github.irgaly.remove-unused-resources:plugin:1.4.1 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares an API of a component compatible with Java 17 and the consumer needed a runtime of a component compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '7.4')
          - Variant 'javadocElements' capability io.github.irgaly.remove-unused-resources:plugin:1.4.1 declares a runtime of a component, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 11)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '7.4')
          - Variant 'runtimeElements' capability io.github.irgaly.remove-unused-resources:plugin:1.4.1 declares a runtime of a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component compatible with Java 17 and the consumer needed a component compatible with Java 11
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '7.4')
          - Variant 'sourcesElements' capability io.github.irgaly.remove-unused-resources:plugin:1.4.1 declares a runtime of a component, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 11)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '7.4')
...