久々にAndroid開発する人のlinter導入ログ

# はじめに

現在転職活動中だが、とある会社の技術試験中に自分のAndroid開発の知識が古すぎることを痛感した。
以前から考えているアイディアでアプリを作ることにより、
現代のAndroid開発の知識を習得し直すことにした。

その時の学びをメモしていく。

## 筆者の知識レベル

自分のAndroidの知識レベルはおおよそ7年前、OSのバージョンだと4が出るかどうかレベルのものだ。
Android StudioやKotlinは普及する前だし、Gradleも触ったことがなかった。

ライフサイクルやcontextの知識はそれなりにあるぐらい。

## 環境

IDEはAndroid Studio Arctic Fox | 2020.3.1 Patch 1、OSはWindows10
さっくりいうなら2022年4月の最新環境である。

# Linter導入

今の自分がAndroidアプリを作るとして、まず手を付けること…
それはコードやプロジェクトの構成に誤りが生じる可能性を十分に下げること。
つまり、linterの導入だ。

Android+Kotlinの場合、手軽に使えるものはAndroidのプロジェクト用のlint、それとktlintのようだ。
lintの方はAndroidアプリを作るときの不具合、ktlintはKotlinのコードのフォーマットがメインと、
それぞれに守備範囲が異なるため、両方導入してしまおう。

## lint(Android)導入

まずは参考用の公式サイトへのリンク。

https://developer.android.com/studio/write/lint

こちらは特に何もすること無く、AndroidStudioのコンソールに```gradlew lint```を入力するだけで動作した。
最終的な使用方法を考え、次のようなオプションをappフォルダ内のbuild.gradleに追記した。
これでAndroidのプロジェクト構成の怪しい部分はひととおり検知できて、少しでも怪しければ止まるようになっている。

```gradle
android {
    // 中略
    lint{
        // If set to true, turns off analysis progress reporting by lint.
        quiet true
        // if true, treat all warnings as errors
        warningsAsErrors true
    }
}
```

## ktlint導入

自分はKotlinは触ったことがなかったため、ここも素直にlinterの力を借りることにした。

こちらもまずは公式のリンクを張っておく。

https://github.com/pinterest/ktlint

今回はコマンドラインから動かすことを最終目的としているため、手動で導入することにした。
その場合は、[Without Plugin](https://github.com/pinterest/ktlint#without-a-plugin)の部分を見て導入すれば良い。

自分の場合は下記のタスクをappのgradleに追加した。(Android Studioで動かすための、両方のlintを動かすタスクも用意した。)

```gradle

configurations {
    ktlint
}

dependencies {
    ktlint "com.pinterest:ktlint:0.43.1"
    // additional 3rd party ruleset(s) can be specified here
    // just add them to the classpath (ktlint 'groupId:artifactId:version') and
    // ktlint will pick them up
}

task ktlint(type: JavaExec, group: "verification") {
    description = "Check Kotlin code style."
    main = "com.pinterest.ktlint.Main"
    classpath = configurations.ktlint
    args "src/**/*.kt", "!src/**/Example*Test.kt"
    // to generate report in checkstyle format prepend following args:
    // "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
    // see https://github.com/pinterest/ktlint#usage for more
}
check.dependsOn ktlint

task all_lint(){
    dependsOn(lint)
    ktlint
}

task ktlintFormat(type: JavaExec, group: "formatting") {
    description = "Fix Kotlin code style deviations."
    main = "com.pinterest.ktlint.Main"
    classpath = configurations.ktlint
    args "-F", "src/**/*.kt", "!src/**/Example*Test.kt"
}

```

これで```gradle all_lint```で文法や構造の確認ができるようになった。

# git hookでlintを強制させる

さて、準備したlintを必ず行わせるようにしたい。
Visual Studioだったらビルド時に任意のコマンドラインを走らせることができるが、
gradleをいろいろ触ってもビルド時にいい感じにlintしてくれるように動かすことはできなかった。

ここはgit hookでコミット前にかならずlintを行い、解析でエラーが出なければOKとしよう。
ちょっとしたtypoの修正をビルドせずに込ってしたときにもチェックしてくれるようになるし、
許容範囲の妥協だ。

また、自分の開発環境はWindowsだから、Gradleを動かすためにはバッチファイルを動かす必要があるから
powershellのスクリプトを動作させよう。

https://qiita.com/manzyun/items/594d722e95315bcdac51

上記リンクを参考に、lintをコミット時に動かすスクリプトを構築した。

```powershell
echo '**start android linter**'
.\gradlew lint > lintresult.log
$studioLint = $LASTEXITCODE
echo '**start kotlin linter**'
.\gradlew ktlint > ktlintresult.log
$ktLint = $LASTEXITCODE

if ($studioLint -ne 0) {
    echo 'lint FAULT!', 'Check "lintresult.log"'
}

if ($ktLint -ne 0){
    echo 'lint FAULT!', 'Check "ktlintresult.log"'
}

if (($studioLint -ne 0) -or ($ktLint -ne 0)){
    exit 1
}

echo 'linter finished'
exit 0
```

lint結果に異常があった場合にどこが問題だったか確認したいためにログを残すようにしている。
また、最後に```exit 0```を行わなければtortoise gitでコミットしたときにコミット結果を出すウィンドウが出続けてしまったため、
横着せずに正常終了を通知するようにした。

わざと改行を増やしたり、無駄なスペースを増やしたりしたソースに対して期待通りコミットが止まったため
正常に動くことが確認できた。