Android Gradle:在构建时动态更改 versionName
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21414399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android Gradle: Dynamically change versionName at build time
提问by German
I'm trying to emulate Maven release plugin in Android by using a customized version of gradle-release plugin: https://github.com/townsfolk/gradle-release
我正在尝试使用自定义版本的 gradle-release 插件在 Android 中模拟 Maven 发布插件:https: //github.com/townsfolk/gradle-release
The interesting steps are:
有趣的步骤是:
- Check uncommitted changes
- Step version code and remove -SNAPSHOT suffix from version name
- Build
- Step version name and add -SNAPSHOT suffix for next development version
- 检查未提交的更改
- 步骤版本代码并从版本名称中删除 -SNAPSHOT 后缀
- 建造
- 步骤版本名称并为下一个开发版本添加 -SNAPSHOT 后缀
However the generated APK always has the previous versions (i.e. 1.0.0-SNAPSHOT instead of 1.0.0).
但是,生成的 APK 始终具有以前的版本(即 1.0.0-SNAPSHOT 而不是 1.0.0)。
Version numbers are stored and correctly updated in gradle.properties, so I'm assuming that I need to update the versions in the data model as well for the changes to take effect.
版本号在 gradle.properties 中存储并正确更新,因此我假设我还需要更新数据模型中的版本以使更改生效。
My android plugin config:
我的 android 插件配置:
defaultConfig {
versionCode versionCode as int // taken from gradle.properties
versionName versionName // taken from gradle.properties
minSdkVersion 10
targetSdkVersion 19
}
Things I tried:
我尝试过的事情:
preBuild << {
android.applicationVariants.each { variant ->
variant.versionName = versionName
}
}
But there's no versionName in a variant.
但是变体中没有 versionName。
preBuild << {
android.buildTypes.each { type ->
type.versionName = versionName
}
}
But there's no versionName in a type.
但是类型中没有 versionName。
preBuild << {
android.productFlavors.each { flavor ->
flavor.versionName = versionName
}
}
But there are no flavors in my app (plain debug and release build types only).
但是我的应用程序中没有任何风格(仅限普通调试和发布构建类型)。
My alternative is to write a bash/bat script to step the versions before invoking Gradle, which pretty much defeats the purpose of using Groovy to improve build customization.
我的替代方法是在调用 Gradle 之前编写一个 bash/bat 脚本来步进版本,这几乎违背了使用 Groovy 改进构建定制的目的。
How can I update versions dynamically in the Android Gradle plugin in the execution phase?
如何在执行阶段在 Android Gradle 插件中动态更新版本?
回答by TWiStErRob
That's what buildTypes
are for. What you're describing is a release
build, IMO.
那buildTypes
是为了什么。你所描述的是一个release
构建,IMO。
Here's an example: when executing assembleDebug
it will give you a snapshot build, and executing assembleRelease
will give you a clean build without any suffix and incremented version number. The next debug build will also use the incremented number.
这是一个例子:执行时assembleDebug
它会给你一个快照构建,执行assembleRelease
会给你一个干净的构建,没有任何后缀和递增的版本号。下一个调试版本也将使用递增的数字。
The following is a fully functional build when the files are created in a folder. It should also work with flavors, but that's just a side product :). Gradle 2.2.1, Android plugin 1.1.3
以下是在文件夹中创建文件时的全功能构建。它也应该适用于口味,但这只是一个副产品:)。Gradle 2.2.1,Android 插件 1.1.3
build.gradle
构建.gradle
apply plugin: 'com.android.application'
apply from: 'auto-version.gradle'
buildscript {
repositories { jcenter() }
dependencies { classpath 'com.android.tools.build:gradle:1.1.3' }
}
android {
buildToolsVersion = "21.1.2"
compileSdkVersion = "android-21"
buildTypes {
debug {
versionNameSuffix "-SNAPSHOT"
}
}
}
println "config code: ${calculateVersionCode()}, name: ${calculateVersionName()}"
src/main/AndroidManifest.xml
src/main/AndroidManifest.xml
<manifest package="com.example" />
auto-version.gradle
自动版本.gradle
ext {
versionFile = new File(project.rootDir, 'version.properties')
calculateVersionName = {
def version = readVersion()
return "${version['major']}.${version['minor']}.${version['build']}"
}
calculateVersionCode = {
def version = readVersion()
def major = version['major'] as int // 1..∞
def minor = version['minor'] as int // 0..99
def build = version['build'] as int // 0..999
return (major * 100 + minor) * 1000 + build
}
}
Properties readVersion() {
def version = new Properties()
def stream
try {
stream = new FileInputStream(versionFile)
version.load(stream)
} catch (FileNotFoundException ignore) {
} finally {
if (stream != null) stream.close()
}
// safety defaults in case file is missing
if(!version['major']) version['major'] = "1"
if(!version['minor']) version['minor'] = "0"
if(!version['build']) version['build'] = "0"
return version
}
void incrementVersionNumber() {
def version = readVersion()
// careful with the types, culprits: "9"++ = ":", "9" + 1 = "91"
def build = version['build'] as int
build++
version['build'] = build.toString()
def stream = new FileOutputStream(versionFile)
try {
version.store(stream, null)
} finally {
stream.close()
}
}
task incrementVersion {
description "Increments build counter in ${versionFile}"
doFirst {
incrementVersionNumber()
}
}
if (plugins.hasPlugin('android') || plugins.hasPlugin('android-library')) {
android {
defaultConfig {
versionName = calculateVersionName()
versionCode = calculateVersionCode()
}
afterEvaluate {
def autoIncrementVariant = { variant ->
if (variant.buildType.name == buildTypes.release.name) { // don't increment on debug builds
variant.preBuild.dependsOn incrementVersion
incrementVersion.doLast {
variant.mergedFlavor.versionName = calculateVersionName()
variant.mergedFlavor.versionCode = calculateVersionCode()
}
}
}
if (plugins.hasPlugin('android')) {
applicationVariants.all { variant -> autoIncrementVariant(variant) }
}
if (plugins.hasPlugin('android-library')) {
libraryVariants.all { variant -> autoIncrementVariant(variant) }
}
}
}
}
Execute gradle assembleDebug
to build normally, gradle assembleRelease
to increment and build, and gradle incrementVersion
to just increment.
Note: be careful with gradle assemble
because the order of assembleDebug
and assembleRelease
will yield different results.
执行gradle assembleDebug
以正常gradle assembleRelease
构建,递增并构建,以及gradle incrementVersion
仅递增。
注意:要小心gradle assemble
,因为秩序assembleDebug
和assembleRelease
会产生不同的结果。
Check the generated files in the build
directory to see if the values are to your liking.
检查build
目录中生成的文件以查看值是否符合您的喜好。
Manual execution (from comments)
手动执行(来自评论)
It is possible you have multiple flavors in which case the version is incremented multiple times because multiple variants match the release build type. The original quesion was for no flavors. If you want to have more control when the version number is incremented just remove the afterEvaluate
block and call the incrementVersion
task whenever you want:
您可能有多种风格,在这种情况下,版本会多次递增,因为多个变体与发布构建类型相匹配。最初的问题是没有味道。如果您想在版本号增加时获得更多控制,只需删除afterEvaluate
块并随时调用incrementVersion
任务:
gradle incrementVersion assembleFreeRelease assemblePaidRelease
(The above manual execution is an untested idea.)
(上面的手动执行是一个未经测试的想法。)
Check uncommitted changes
检查未提交的更改
The "Check uncommitted changes" are not covered in this answer, that's another game. You could hook on to tasks.preBuild.doFirst { /*fail here if uncommited changes*/ }
if I understand correctly. But that highly depends on your version control. Ask another question for more!
此答案未涵盖“检查未提交的更改”,这是另一款游戏。tasks.preBuild.doFirst { /*fail here if uncommited changes*/ }
如果我理解正确,你可以上钩。但这在很大程度上取决于您的版本控制。再问一个问题!
回答by Javanator
I needed to append current git commit count of code revision to the version name. Its real handy in many situation. I ended up with below simple gradle file
我需要将代码修订的当前 git 提交计数附加到版本名称。在许多情况下它真的很方便。我最终得到了以下简单的 gradle 文件
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
def gitCommitCount = "git rev-list HEAD --count".execute().text.trim()
defaultConfig {
applicationId "my.app.package.name"
minSdkVersion 16
targetSdkVersion 21
versionCode 6
versionName "0.8"
}
buildTypes {
debug {
versionNameSuffix ".${gitCommitCount}"
}
release {
versionNameSuffix ".${gitCommitCount}"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
Similar to gitCommitCount, You can generate variables of your own to customise version name. As i am just executing a terminal command to store its result in a variable.
与 gitCommitCount 类似,您可以生成自己的变量来自定义版本名称。因为我只是执行终端命令以将其结果存储在变量中。
回答by Bryan Herbst
This doesn't directly address your question of how to completely change the versionName, but this is what I use to append a suffix for my buildTypes:
这并没有直接解决您如何完全更改 versionName 的问题,但这是我用来为我的 buildTypes 附加后缀的问题:
defaultConfig {
versionName "1.0"
}
buildTypes {
debug {
versionNameSuffix "-SNAPSHOT"
}
}
回答by Neil B
I just used Javanator's answerand modified it a bit so that commit count not only helps in changing the name but also makes sure that version code also remains unique. Here is a sample of what I did (Maybe a couple of things can be optimized, but nevertheless does the job for me) :
我只是使用了Javanator 的答案并对其进行了一些修改,以便提交计数不仅有助于更改名称,而且还确保版本代码也保持唯一。这是我所做的一个示例(也许可以优化一些事情,但仍然对我有用):
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
def gitCommitCount = "git rev-list HEAD --count".execute().text.trim().toBigInteger()
project.ext.set("versionCode", gitCommitCount)
project.ext.set("versionNameSuffix", "(${gitCommitCount})")
defaultConfig {
applicationId "my.app.package.name"
minSdkVersion 15
targetSdkVersion 25
versionCode project.versionCode
versionName "1.0"
versionNameSuffix project.versionNameSuffix
setProperty("archivesBaseName", "MyProject-$versionName")
....
}
signingConfigs {
config {
.........
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
}
packagingOptions {
.....
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
}
}
}
Edit :The last bit could also be like
编辑:最后一点也可能像
applicationVariants.all { variant ->
if (variant.name.contains('release')) {
variant.outputs.each { output ->
variant.outputs.all {
outputFileName = "MyProject-${variant.versionName}${variant.versionCode}.apk"
}
}
}
}
回答by Sean
I was facing similar need of having separate build logic for release and non-release builds. Apart from different versioning, I had to use a different set of dependencies, even different repositories.
我面临着类似的需求,即为发布和非发布构建拥有单独的构建逻辑。除了不同的版本之外,我还必须使用不同的依赖项集,甚至是不同的存储库。
None of the available plugins had all of the features that I needed, so I developed my own solution, based on simple approach - command line argument.
可用的插件都没有我需要的所有功能,所以我开发了自己的解决方案,基于简单的方法 - 命令行参数。
You can pass a command line parameter when invoking gradle build script like this:
您可以在调用 gradle 构建脚本时传递命令行参数,如下所示:
gradle build -PmyParameter=myValue
or in my case
或者就我而言
gradle build -PisRelease=true
Gradle will parse it, and it would automagically be available as a property of the project object. You could then use it like this:
Gradle 将解析它,它会自动作为项目对象的属性可用。然后你可以像这样使用它:
if (project.hasProperty('isRelease') && project.isRelease) {
// Here be the logic!
}
I extracted this logic into a separate plugin, and I've been successfully using it across different projects.
我将此逻辑提取到一个单独的插件中,并且我已经在不同的项目中成功地使用了它。
Although this doesn't answer your question directly, I hope I gave you another angle to think about the problem and another possible solution.
虽然这不能直接回答你的问题,但我希望我给了你另一个角度来思考这个问题和另一个可能的解决方案。