自动版本管理
源:Semantic Versioning | Git Version Plugin
自动化管理应用版本号,集成 Git 信息,实现版本追踪和发布管理。
版本号概念
Android 版本号
versionCode:
- 整数类型
- 用于版本比较
- 每次发布递增
- Google Play 要求
versionName:
- 字符串类型
- 展示给用户
- 遵循语义化版本
语义化版本
格式:
<major>.<minor>.<patch>[-<label>][+<build>]
1.0.0 - 正式版本
1.0.0-alpha01 - Alpha 版本
1.0.0-beta01 - Beta 版本
1.0.0-rc01 - Release Candidate
1.0.1 - 补丁版本
1.1.0 - 次要版本
2.0.0 - 主要版本规则:
- MAJOR:不兼容的 API 变更
- MINOR:向后兼容的功能
- PATCH:向后兼容的修复
基本版本管理
gradle.properties 配置
gradle.properties:
properties
VERSION_NAME=1.0.0
VERSION_CODE=1build.gradle.kts:
kotlin
android {
defaultConfig {
versionCode = findProperty("VERSION_CODE").toString().toInt()
versionName = findProperty("VERSION_NAME").toString()
}
}版本号自增
创建脚本:
kotlin
// buildSrc/src/main/kotlin/VersionManager.kt
object VersionManager {
fun getVersionCode(): Int {
val props = java.util.Properties()
file("version.properties").inputStream().use { props.load(it) }
return props.getProperty("VERSION_CODE").toInt()
}
fun getVersionName(): String {
val props = java.util.Properties()
file("version.properties").inputStream().use { props.load(it) }
return props.getProperty("VERSION_NAME")
}
fun incrementVersionCode() {
val props = java.util.Properties()
val file = file("version.properties")
file.inputStream().use { props.load(it) }
val versionCode = props.getProperty("VERSION_CODE").toInt() + 1
props.setProperty("VERSION_CODE", versionCode.toString())
file.outputStream().use { props.store(it, null) }
}
}使用:
kotlin
android {
defaultConfig {
versionCode = VersionManager.getVersionCode()
versionName = VersionManager.getVersionName()
}
}
tasks.register("incrementVersion") {
doLast {
VersionManager.incrementVersionCode()
}
}Git 集成
使用 Git Tag
获取最新 Tag:
kotlin
fun getGitTag(): String {
val process = Runtime.getRuntime().exec("git describe --tags --always")
val tag = process.inputStream.bufferedReader().readText().trim()
return if (tag.startsWith("v")) tag.substring(1) else tag
}
android {
defaultConfig {
versionName = getGitTag()
}
}使用 Provider API(推荐):
kotlin
val gitTag = providers.exec {
commandLine("git", "describe", "--tags", "--always")
}.standardOutput.asText.map { it.trim() }
android {
defaultConfig {
versionName = gitTag.get()
}
}Git Commit Hash
kotlin
val gitCommit = providers.exec {
commandLine("git", "rev-parse", "--short", "HEAD")
}.standardOutput.asText.map { it.trim() }
android {
defaultConfig {
buildConfigField("String", "GIT_HASH", "\"${gitCommit.get()}\"")
}
}Git Branch
kotlin
val gitBranch = providers.exec {
commandLine("git", "branch", "--show-current")
}.standardOutput.asText.map { it.trim() }
android {
buildTypes {
debug {
versionNameSuffix = "-${gitBranch.get()}"
}
}
}自动化版本号
基于 Git Commits
kotlin
fun getVersionCode(): Int {
val process = Runtime.getRuntime().exec("git rev-list --count HEAD")
return process.inputStream.bufferedReader().readText().trim().toInt()
}
android {
defaultConfig {
versionCode = getVersionCode()
}
}基于 Git Tags
kotlin
fun parseVersion(): Pair<Int, String> {
val tag = providers.exec {
commandLine("git", "describe", "--tags", "--abbrev=0")
}.standardOutput.asText.get().trim()
val versionName = tag.removePrefix("v")
val parts = versionName.split(".")
val versionCode = parts[0].toInt() * 10000 + parts[1].toInt() * 100 + parts[2].toInt()
return versionCode to versionName
}
val (versionCode, versionName) = parseVersion()
android {
defaultConfig {
this.versionCode = versionCode
this.versionName = versionName
}
}插件方案
Git Version Plugin
添加插件:
kotlin
plugins {
id("com.gladed.androidgitversion") version "0.4.14"
}
androidGitVersion {
codeFormat = "MNNPPPP" // Major, Minor, Patch
format = "%tag%"
}
android {
defaultConfig {
versionCode = androidGitVersion.code()
versionName = androidGitVersion.name()
}
}Semantic Versioning Plugin
kotlin
plugins {
id("net.nemerosa.versioning") version "3.0.0"
}
versioning {
versionPrefix = "v"
}
android {
defaultConfig {
versionName = versioning.info.display
}
}BuildConfig 集成
添加构建信息
kotlin
val gitCommit = providers.exec {
commandLine("git", "rev-parse", "--short", "HEAD")
}.standardOutput.asText.map { it.trim() }
val buildTime = providers.provider {
java.time.Instant.now().toString()
}
android {
defaultConfig {
buildConfigField("String", "GIT_COMMIT", "\"${gitCommit.get()}\"")
buildConfigField("String", "BUILD_TIME", "\"${buildTime.get()}\"")
}
}使用:
kotlin
val versionInfo = """
Version: ${BuildConfig.VERSION_NAME}
Build: ${BuildConfig.VERSION_CODE}
Commit: ${BuildConfig.GIT_COMMIT}
Time: ${BuildConfig.BUILD_TIME}
""".trimIndent()多环境版本
Flavor 版本
kotlin
android {
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
versionNameSuffix = "-dev"
}
create("staging") {
dimension = "environment"
versionNameSuffix = "-staging"
}
create("prod") {
dimension = "environment"
}
}
}Build Type 版本
kotlin
android {
buildTypes {
debug {
versionNameSuffix = "-debug"
applicationIdSuffix = ".debug"
}
release {
// 正式版本
}
}
}实战案例
案例1:完整版本管理系统
kotlin
// buildSrc/src/main/kotlin/VersionConfig.kt
object VersionConfig {
private val gitTag = providers.exec {
commandLine("git", "describe", "--tags", "--abbrev=0", "--match", "v*")
}.standardOutput.asText.map { it.trim().removePrefix("v") }
private val gitCommitCount = providers.exec {
commandLine("git", "rev-list", "--count", "HEAD")
}.standardOutput.asText.map { it.trim().toInt() }
private val gitCommitHash = providers.exec {
commandLine("git", "rev-parse", "--short", "HEAD")
}.standardOutput.asText.map { it.trim() }
fun versionCode(): Int = gitCommitCount.get()
fun versionName(): String {
val tag = gitTag.getOrElse("0.0.0")
val hash = gitCommitHash.get()
return "$tag ($hash)"
}
fun buildTime(): String = java.time.Instant.now().toString()
}使用:
kotlin
android {
defaultConfig {
versionCode = VersionConfig.versionCode()
versionName = VersionConfig.versionName()
buildConfigField("String", "BUILD_TIME", "\"${VersionConfig.buildTime()}\"")
}
}案例2:CI 版本号
kotlin
val isCI = providers.environmentVariable("CI")
.map { it.toBoolean() }
.getOrElse(false)
val buildNumber = providers.environmentVariable("BUILD_NUMBER")
.orElse("0")
android {
defaultConfig {
versionCode = if (isCI) {
buildNumber.get().toInt()
} else {
1
}
versionNameSuffix = if (isCI) "-ci${buildNumber.get()}" else "-local"
}
}最佳实践
使用 Git Tags:
- 标记发布版本
- 自动生成版本号
- 追踪历史版本
Provider API:
kotlin
// ✅ 推荐
val version = providers.exec { ... }.standardOutput.asText
// ❌ 避免
val version = "git ...".execute().text版本号规范:
- versionCode:自动递增
- versionName:语义化版本
- BuildConfig:记录构建信息
环境区分:
kotlin
debug {
versionNameSuffix = "-debug"
}CI/CD 集成:
- 使用环境变量
- 自动化版本号
- 标记发布版本