麦芽を支える技術

麦芽(ばくが、英語:malt)とは、麦、特に大麦の種子を発芽させたもので、ビール、ウイスキー、水飴の原料となる。(Wikipediaより)

AndroidのversionCode, versionNameをインクリメントするGradleタスク

AndroidプロジェクトのversionCodeやversionNameは、だいたい1つずつインクリメントしていくだけの場合が多く、コマンド1発で書き換えられるようにしておけば、将来的にCIなどでこの辺の作業を自動化させる時にも楽だよね、というヤツです。

iOSプロジェクトだとfastlaneの increment_build_numberincrement_version_number のActionで同様のことができますが、手元のAndroidプロジェクトだとfastlaneは使わずGradleでほとんどのビルドタスクを実行しているので、自前のGradleタスクとして用意しました。

Gradleタスク内容

versionCodeのインクリメント

[build.gradle]

task incrementVersionCode {
    doFirst {
        println("Incrementing Version Code...")
        def pattern = "versionCode (\\d+)"
        def manifestFile = file("./app/build.gradle")
        def manifestText = manifestFile.getText()

        def code = Integer.parseInt((manifestText =~ pattern)[0][1])
        def nextCode = code + 1

        // 番号直接指定の場合
        if (project.hasProperty("num")) {
            def num = project.property("num")
            if (num != "" && num.isInteger()) {
                nextCode = num
            }
        }

        println("Set versionCode(" + code + ") to " + nextCode);
        def manifestContent = manifestText.replaceAll(pattern, "versionCode " + nextCode)
        manifestFile.write(manifestContent)
    }
}

Usage

単純インクリメント
$ ./gradlew incrementVersionCode
         minSdkVersion 23
         targetSdkVersion 29
-        versionCode 11
+        versionCode 12
         versionName "1.3.0"
versionCode指定
$ ./gradlew incrementVersionCode -Pnum=50
         minSdkVersion 23
         targetSdkVersion 29
-        versionCode 11
+        versionCode 50
         versionName "1.3.0"

versionNameのインクリメント

[build.gradle]

task incrementVersionName {
    doFirst {
        println("Incrementing Version Name...")
        def pattern = "versionName \"(\\d+)\\.(\\d+)\\.(\\d+)\""
        def manifestFile = file("./app/build.gradle")
        def manifestText = manifestFile.getText()

        def versionNames = (manifestText =~ pattern)[0]
        def major = Integer.parseInt(versionNames[1])
        def minor = Integer.parseInt(versionNames[2])
        def patch = Integer.parseInt(versionNames[3])
        def nextVersionName = major + "." + minor + "." + (patch + 1)   // Default

        if (project.hasProperty("type")) {
            def type = project.property("type")
            if (type == "minor") {
                nextVersionName = major + "." + (minor + 1) + ".0"
            } else if (type == "major") {
                nextVersionName = (major + 1) + ".0.0"
            }
        }

        println("Set VersionName to " + nextVersionName);

        def manifestContent = manifestText.replaceAll(pattern, "versionName \"" + nextVersionName + "\"")
        manifestFile.write(manifestContent)
    }
}

Usage

Patchバージョンインクリメント
$ ./gradlew incrementVersionName 
         minSdkVersion 23
         targetSdkVersion 29
         versionCode 11
-        versionName "1.3.0"
+        versionName "1.3.1"
Minorバージョンインクリメント
$ ./gradlew incrementVersionName -Ptype=minor
         minSdkVersion 23
         targetSdkVersion 29
         versionCode 11
-        versionName "1.3.0"
+        versionName "1.4.0"
Majorバージョンインクリメント
$ ./gradlew incrementVersionName -Ptype=major
         minSdkVersion 23
         targetSdkVersion 29
         versionCode 11
-        versionName "1.3.0"
+        versionName "2.0.0"

おわりに

とりあえずタスクを動かすことが目的であんまりコードの書き方にこだわって無いので、コード自体はもうちょっと整理できそうな気がしますね。

ただ、今はちょっとGroovy言語仕様を調べるモチベーションになれてないので、まぁリファクタは追々...。