Androidアプリ開発 FindBugs terminalでAndroid GradleのFindBugsを実行する

2017年12月24日(編集2017年12月24日)
このエントリーをはてなブックマークに追加

Androidアプリ開発では、FindBugsを利用することでJavaコードの潜在的なバグを発見することができます。
この記事は、Android GradleでFindBugsを利用する方法を記載した記事です。

環境はAndroid 8.1 (API level 27) です。

環境

  • macOS Sierra
  • android sdk 27
  • Oracle jdk version 1.8.0_72
  • Android Studio 3.0.1
  • kotlin 1.2.10
  • com.android.tools.build:gradle:3.0.1

難易度

中級者向け

サンプルコード

Android-Env-Demo

FindBugs

FindBugsは、Java code内のバグをさがす静的解析ツールです。
アプリ開発時は、積極的に使いましょう。

Android Gradle

GradleでFindBugsを動作させるプラグインは公式サイトで紹介されていますが、 AndroidのGradleはそのままでは動きません。

AndroidのGradleでFindBugsを動かす方法は2つありますが、この記事では、多くのプロジェクトで利用されているカスタム実装の方法を説明します。

Gradle実装未経験の場合

GradleはGroovyで実装されています。もしあなたが設定だけで1度もソースコードを記述したことない場合は、ドキュメントのChapter 16, Chapter 8, Chapter 25を読みながらコードを写経することをお勧めします。4,5時間も手を動かせば、Gradleの設定で使う程度の知識は身につきます。

設定

app/build.gradleに設定を記載します。

{project_folder}/app/build.gradle
apply plugin: 'findbugs'

task customFindbugs(type: FindBugs) {
    ignoreFailures = false
    effort = "max"
    reportLevel = "low"

    classes = files("$project.buildDir/intermediates/classes")

    // Use this only if you want exclude some errors
    excludeFilter = file("$rootProject.rootDir/config/findbugs/exclude.xml")

    source = fileTree('src/main/java/')
    classpath = files()

    reports {
        xml.enabled false
        html.enabled true
        html.setDestination(file("$project.buildDir/outputs/findbugs/findbugs-output.html"))
    }
}

check.dependsOn customFindbugs
          

■ 実装の解説

1. apply plugin

FindBugsプラグインを使用するには、ビルドスクリプトに以下のコードを含めます。

apply plugin: 'findbugs'
        

このプラグインを適用すると、品質チェックを実行する多くのタスクが追加されます。

2. findbugsタスクの実装

AndroidのGradleではFindBugs pluginで用意されているデフォルトのタスクこのままでは実行できないので、自分でタスクを実装する必要があります。

task customFindbugs(type: FindBugs) {
}
        

タスク名は何でも構いません。customFindbugsや、findbugsと命名するのが一般的だと思います。
タスクの引数はFindBugsの型を指定します。

(type: FindBugs)
        

FindBugsは、org.gradle.api.plugins.qualityパッケージで用意されているFindBugs.javaクラスです。
Javaで説明すると、FindBugsクラスを引数に取るcustomFindbugsメソッドです。

3. プロパティの設定

タスク内で必要なプロパティの設定を行います。

ignoreFailures = false
effort = "max"
reportLevel = "low"

classes = files("$project.buildDir/intermediates/classes")

// Use this only if you want exclude some errors
excludeFilter = file("$rootProject.rootDir/config/findbugs/exclude.xml")

source = fileTree('src/main/java/')
classpath = files()
        

各プロパティはsetterメソッドです。値は引数です。
ignoreFailuresプロパティならorg.gradle.api.plugins.quality.FindBugs.javaのsetIgnoreFailuresメソッドを呼び出して、引数にfalseを引き渡します。

    /**
     * Whether to allow the build to continue if there are warnings.
     */
    public void setIgnoreFailures(boolean ignoreFailures) {
        this.ignoreFailures = ignoreFailures;
    }
        

他のプロパティも同様です。

classes, excludeFilter, source, classpathは必ず設定する必要があります。設定しないと実行に失敗します。

exclude.xmlは指定したフォルダに以下のexclude.xmlを置きます。

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <Class name="~.*.R"/>
    </Match>
    <Match>
        <Class name="~.*.R$.*"/>
    </Match>
</FindBugsFilter>
        

4. reportsプロパティの設定

reportsプロパティはファイルの種類や出力場所を設定します。

reports {
    xml.enabled false
    html.enabled true
    html.destination "$project.buildDir/outputs/findbugs/findbugs-output.html"
}
        

reportsプロパティはクロージャを引数に取ります。org.gradle.api.plugins.quality.FindBugs.javaのreportsメソッドは以下のように実装されています。

public FindBugsReports reports(Closure closure) {
    return reports(new ClosureBackedAction<FindBugsReports>(closure));
}
        

公式サイトやネットで検索すると、html出力場所にhtml.destinationプロパティを使っていますが、gradle4.4ではdeprecatedになっています。
なので、以下のように修正します。

    reports {
        xml.enabled false
        html.enabled true
        html.setDestination(file("$project.buildDir/outputs/findbugs/findbugs-output.html"))
    }
        

上記のように変更すると、deprecatedの警告が消えます。

5. taskに追加

上記で設定したタスクをcheckタスク実行時に動作するようにします。

check.dependsOn customFindbugs
        

ビルド時に実行したい場合は、checkではなく、buildに設定すれば、build時にも実行されます。

build.dependsOn customFindbugs
        

6. ファイル分割

FindBugsはカスタマイズが必要なので、build.gradleファイルの行数が増えてコードが読みにくくります。なので、FindBugsの部分だけ別ファイルに分離します。ファイル名はfindBugs.gradleとしてappフォルダ に配置します。
分離したファイルを利用するには、apply fromを使います。

apply from: 'findBugs.gradle'
        

これでコードの可読性が向上します。

ビルド

上記のコードの動作を確認してみましょう。
terminalで以下のコマンドを実行します。

terminal
cd {rootProject.rootDir}
./gradlew check

Execution failed for task ':app:customFindbugs'.
> FindBugs rule violations were found. See the report at: file:///Users/java-programming/workspace/android/Android-Library-Demo/app/build/outputs/findbugs/findbugs-output.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

* Get more help at https://help.gradle.org

BUILD FAILED in 8s

          

うまく実行されました。ignoreFailures = falseなので、バグを0にしないとビルドに失敗します。ignoreFailures = trueにすると、バグが0でなくてもビルドが可能になります。
なるべくignoreFailures = falseでFindBugsを実行可能にしましょう。

結論

Android GradleでFindBugsの設定をする場合は、GradleとGroovyの両方の知識があると役立ちます。Javaやkotlinを取得しているAndroidエンジニアであれば、学習コストは低いので、この機会に学習してしましょう。

関連記事

タグ検索で調べてみよう

Android8.1 FindBugs 環境