LoginSignup
6
2

Android プロジェクトの未使用リソースをコマンドラインや CI で削除する (Remove Unused Resources Plugin)

Last updated at Posted at 2022-01-21

Android プロジェクトの未使用リソースを一括で削除する Gradle Plugin を公開しました。このプラグインのメリットや使い方を解説します。

2023/08/08: v2.1.0 に合わせて更新
2023/08/05: Remove Unused Resources Plugin for Android v2.0.0 の内容に更新しました

Remove Unused Resources Plugin for Android

Remove Unused Resources Plugin により、Gradle Task から Android の未使用リソースを削除できるようになります。

特徴やメリット

  • Android Lint UnusedResources ルールの実行結果 lint-results.xml をもとにリソースの削除を実行します
    • 未使用リソースの検出は Android Lint に任せているため、Android Studio の Refactor > Remove Unused Resources... メニューと同じ結果を期待できます

Android Studio の Remove Unused Resources メニュー

  • マルチモジュールプロジェクト対応
    • Android Lint がマルチモジュールプロジェクトでのリソース検出に対応しています
  • DataBinding, Epoxy 対応
    • Android Lint がコード生成解析 (checkGeneratedSources) に対応しているため、正しく解析できます
  • Github Actions などの CI での実行に適しています
    • Gradle Task であるためどこでも実行できます
  • Android リソースのすべての形式に対応しています
    • Resource Type のすべてに対応しています
    • R.string などの XML tag の削除も、R.layout などのリソースファイル削除も対応しています
    • drawable-{density} や values-v26 などの Alternative リソースも正しく検出します
    • 9-patch ファイルも正しく検出します
  • もとの XML をなるべく維持する
    • XML 内のリソースを削除するときに、もとの XML のインデントやスペースを維持します
    • &#{unicode} などの文字列参照なども元の XML の表現をそのまま残して処理します
  • 高速動作
    • ファイルや XML tag の削除以外の無駄な処理はしていません
    • Android Lint タスクで未使用リソースを検出する仕組みのため、実行時間のほとんどは Android Lint に割かれると思います

前提

Android マルチモジュールで Gradle Kotlin Script (*.gradle.kts) 構成のプロジェクトを前提として説明します。

Gradle や Android Gradle Plugin のバージョンなど必要要件は README.md を参照してください。

使い方

このプラグインでは新しい Gradle Plugin Management に対応しています。settings.gradle.kts へ以下の設定を追加します。

settings.gradle.kts

// ...
pluginManagement {
  repositories {
    google()
    mavenCentral()
    gradlePluginPortal() // Remove Unused Resources Plugin は Gradle Plugin Portal へ登録されています
  }
}
// ...

Android アプリモジュールへ Remove Unused Resources Plugin を適用します。

app/build.gradle.kts

plugins {
  id("io.github.irgaly.remove-unused-resources") version "{最新バージョンを指定}"
}

DataBinding や Epoxy などのコード生成を使っている場合は、生成コードも解析対象に含めるために、コード生成をしているモジュールごとに checkGeneratedSources を設定します。

app/build.gradle.kts

android {
  lint {
    // コード生成を使っているモジュールでは checkGeneratedSources を有効にする
    checkGeneratedSources = true
  }
}

othermodule/build.gradle.kts

android {
  lint {
    // コード生成を使っているモジュールでは checkGeneratedSources を有効にする
    // rur.lint.onlyUnusedResources オプションを使用する場合はモジュール個別の定義は不要になります
    checkGeneratedSources = true
  }
}

これで Remove Unused Resources Plugin を実行する準備は整いました。

Android Lint を実行して UnusedResource を検出し、app/build/reports/lint-results-{variant}.xml を生成します。

ここでは variant = debug とします。

% ./gradlew :app:lintDebug

Android Lint の結果にもとづいてリソースを削除します。削除されるリソースを確認するために Dry Run で実行してみます。Dry Run モードでは削除対象を列挙するだけで実際には削除を実行しません。

(オプションの rur は Remove Unused Resources の頭文字です)

% ./gradlew :app:removeUnusedResourcesDebug -Prur.dryRun
...
> Task :app:removeUnusedResourcesDebug
> Task :app:removeUnusedResourcesDebug
> report from: /src/project/app/src/main/res/values/colors.xml
[dry run] delete resource element: R.color.black
[dry run] delete resource element: R.color.unused_color
[dry run] delete resource element: R.color.unused_color_with_night_theme
skip because it has tools:override: R.color.unused_override
> report from: /src/project/app/src/main/res/values/strings.xml
[dry run] delete resource element: R.string.unused_string
> report from: /src/project/app/src/main/res/values-night/colors.xml
[dry run] delete resource element: R.color.unused_color_with_night_theme
[dry run] delete resource file because of empty: /src/project/app/src/main/res/values-night/colors.xml
...

結果を確認して問題なさそうであれば -Prur.dryRun 引数を消して実際に削除を実行します。

% ./gradlew :app:removeUnusedResourcesDebug
...
> Task :app:removeUnusedResourcesDebug
> report from: /src/project/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
skip because it has tools:override: R.color.unused_override
> report from: /src/project/app/src/main/res/values/strings.xml
delete resource element: R.string.unused_string
> report from: /src/project/app/src/main/res/values-night/colors.xml
delete resource element: R.color.unused_color_with_night_theme
delete resource file because of empty: /src/project/app/src/main/res/values-night/colors.xml
...

未使用のリソースファイルや、未使用リソースの XML tag が削除されました。

たとえば、values 以下のファイルの XML tag は以下のように削除されます。

--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,8 +6,6 @@
     <color name="teal_700">#FF018786</color>
     <color name="black">#FF000000</color>
     <color name="white">#FFFFFFFF</color>
-    <color name="unused_color">#FFFFFF</color>
-    <color name="unused_color_with_night_theme">#FFFFFF</color>
     <color name="unused_exclude_color">#FFFFFF</color>
     <color name="unused_exclude_pattern_color">#FFFFFF</color>
 </resources>

UnusedResources ルールだけの Android Lint を実行する

Android Lint をそのまま実行すると UnusedResources 以外の Lint も実行してしまうため時間がかかってしまいます。

未使用リソースを検出するだけでよければ UnusedResources ルールだけのチェックをすると効率的です。

Remove Unused Resources Plugin を適用していれば以下のオプションを指定することで UnusedResources ルールだけをチェックすることができます。

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

このオプションを指定すると、以下の設定で lintOptions を上書きすることになります。

android {
  lint {
    // -Prur.lint.onlyUnusedResources オプションを付けると、以下の設定が自動で適用されます
    xmlReport = true // app project のみ
    checkDependencies = true // app project のみ
    checkGeneratedSources = true
    checkOnly.clear()
    checkOnly.add("UnusedResources")
    warning.add("UnusedResources")
  }
}

オプションについて、詳しくは README.md を参照してください。

CI からリソース削除を実行する

Github Actions などの CI 環境で自動的に不要リソースを削除し、不要リソース削除の PR や commit を生成するようにすると便利です。

CI で実行する場合はたとえば以下のコマンドのようになります。

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

このコマンドは以下の処理を実行します。

  • UnusedResources ルールのみで Android Lint を実行する
  • Android Lint の結果 app/build/reports/lint-results-debug.xml に従って、未使用リソースを削除する

リソース削除の除外設定

Android Lint で検出されても削除したくないリソースを設定しておくことができます。

app/build.gradle.kts

removeUnusedResources {
  // 文字列 "R.{type}.{resource name}" との完全一致で除外リソースを指定する
  excludeIds.add("R.color.unused_exclude_color")

  // 文字列 "R.{type}.{resource name}" に対して正規表現(完全一致)で除外リソースを指定する
  excludeIdPatterns.add("R\\..*exclude_pattern.*")

  // 削除対象のリソースファイルに対して File glob 形式で、除外リソースを指定する
  // ここで指定したファイルやファイル内の XML tag は削除対象から除外されます
  excludeFilePatterns.add("**/values/exclude_colors.xml")
}

設定について、詳しくは README.md を参照してください。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2