Android 具有 gradle 额外属性的自动增量 VersionCode
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21405457/
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
Autoincrement VersionCode with gradle extra properties
提问by carvaq
I'm building an Android app with gradle. Until now I used the Manifest file to increase the versionCode, but I would like to read the versionCode from an external file and depending if it is the release flavor or the debug flavor increase the versionCode. I tried the extra properties, but you can't save them, which means that next time I build it I'm getting the same versionCode. Any help would be very much appreciated!
我正在用 gradle 构建一个 Android 应用程序。到目前为止,我使用 Manifest 文件来增加 versionCode,但我想从外部文件中读取 versionCode,并根据它是发布风格还是调试风格来增加 versionCode。我尝试了额外的属性,但您无法保存它们,这意味着下次构建它时我会得到相同的 versionCode。任何帮助将不胜感激!
project.ext{
devVersionCode = 13
releaseVersionCode = 1
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile project(':Cropper')
compile "com.android.support:appcompat-v7:18.0.+"
compile "com.android.support:support-v4:18.0.+"
compile fileTree(dir: 'libs', include: '*.jar')
}
def getReleaseVersionCode() {
def version = project.releaseVersionCode + 1
project.releaseVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getDevVersionCode() {
def version = project.devVersionCode + 1
project.devVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getLastVersioName(versionCode) {
return "0.0." + versionCode
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 9
targetSdkVersion 19
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
buildTypes {
release {
runProguard true
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFile 'proguard.cfg'
debuggable false
signingConfig null
zipAlign false
}
debug {
versionNameSuffix "-DEBUG"
}
}
productFlavors {
dev {
packageName = 'com.swisscom.docsafe.debug'
versionCode getDevVersionCode()
versionName getLastVersioName(project.devVersionCode)
}
prod {
packageName = 'com.swisscom.docsafe'
versionCode getReleaseVersionCode()
versionName getLastVersioName(project.releaseVersionCode)
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
回答by CommonsWare
I would like to read the versionCode from an external file
我想从外部文件中读取 versionCode
I am sure that there are any number of possible solutions; here is one:
我相信有许多可能的解决方案;这是一个:
android {
compileSdkVersion 18
buildToolsVersion "18.1.0"
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def code = versionProps['VERSION_CODE'].toInteger() + 1
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode code
versionName "1.1"
minSdkVersion 14
targetSdkVersion 18
}
}
else {
throw new GradleException("Could not read version.properties!")
}
// rest of android block goes here
}
This code expects an existing version.properties
file, which you would create by hand before the first build to have VERSION_CODE=8
.
此代码需要一个现有version.properties
文件,您将在第一次构建之前手动创建该文件,该文件具有VERSION_CODE=8
.
This code simply bumps the version code on each build -- you would need to extend the technique to handle your per-flavor version code.
这段代码只是在每次构建时修改版本代码——您需要扩展该技术来处理您的每个风格的版本代码。
You can see the Versioning sample projectthat demonstrates this code.
您可以查看演示此代码的版本控制示例项目。
回答by just_user
Here comes a modernization of my previous answer which can be seen below. This one is running with Gradle 4.4and Android Studio 3.1.1.
这是我以前的答案的现代化,可以在下面看到。这个是在Gradle 4.4和Android Studio 3.1.1 上运行的。
What this script does:
这个脚本的作用:
- Creates a version.propertiesfile if none exists (up vote Paul Cantrell's answer below, which is where I got the idea from if you like this answer)
- For each build, debug release or any time you press the run button in Android Studio the VERSION_BUILD number increases.
- Every time you assemble a release your Android versionCodefor the play store increases and your patch numberincreases.
- Bonus: After the build is done copies your apk to
projectDir/apk
to make it more accessible.
- 如果不存在,则创建一个version.properties文件(对下面 Paul Cantrell 的回答投上一票,如果你喜欢这个答案,我就是从这里得到这个想法的)
- 对于每个构建、调试版本或任何时候在 Android Studio 中按下运行按钮,VERSION_BUILD 数字都会增加。
- 每次您组装一个发行版时,您的 Play 商店的Android版本代码都会增加,并且您的补丁号也会增加。
- 奖励:构建完成后,将您的 apk 复制到
projectDir/apk
以使其更易于访问。
This script will create a version number which looks like v1.3.4 (123)
and build an apk file like AppName-v1.3.4.apk.
此脚本将创建一个看起来像的版本号v1.3.4 (123)
并构建一个类似AppName-v1.3.4.apk的 apk 文件。
Major version ? ? Build version
v1.3.4 (123)
Minor version ?|? Patch version
Major version:Has to be changed manually for bigger changes.
主要版本:必须手动更改以进行更大的更改。
Minor version:Has to be changed manually for slightly less big changes.
次要版本:必须手动更改以进行较小的更改。
Patch version:Increases when running gradle assembleRelease
补丁版本:运行时增加gradle assembleRelease
Build version:Increases every build
构建版本:增加每次构建
Version Number:Same as Patch version, this is for the version code which Play Store needs to have increased for each new apk upload.
版本号:与Patch version相同,这是 Play Store 需要为每个新的 apk 上传增加的版本代码。
Just change the content in the comments labeled 1 - 3 below and the script should do the rest. :)
只需更改下面标记为 1 - 3 的注释中的内容,脚本就可以完成剩下的工作。:)
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['VERSION_PATCH'] = "0"
versionProps['VERSION_NUMBER'] = "0"
versionProps['VERSION_BUILD'] = "-1" // I set it to minus one so the first build is 0 which isn't super important.
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
if ('assembleRelease' in runTasks) {
value = 1
}
def mVersionName = ""
def mFileName = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps['VERSION_NUMBER'] = (versionProps['VERSION_NUMBER'].toInteger() + value).toString()
versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString()
versionProps.store(versionPropsFile.newWriter(), null)
// 1: change major and minor version here
mVersionName = "v1.0.${versionProps['VERSION_PATCH']}"
// 2: change AppName for your app name
mFileName = "AppName-${mVersionName}.apk"
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
applicationId "com.example.appname" // 3: change to your package name
versionCode versionProps['VERSION_NUMBER'].toInteger()
versionName "${mVersionName} Build: ${versionProps['VERSION_BUILD']}"
}
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
if ('assembleRelease' in runTasks) {
applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
outputFileName = mFileName
}
}
}
}
task copyApkFiles(type: Copy){
from 'build/outputs/apk/release'
into '../apk'
include mFileName
}
afterEvaluate {
assembleRelease.doLast {
tasks.copyApkFiles.execute()
}
}
signingConfigs {
...
}
buildTypes {
...
}
}
====================================================
================================================== ==
INITIAL ANSWER:
初始答案:
I want the versionName to increase automatically as well. So this is just an addition to the answer by CommonsWare which worked perfectly for me. This is what works for me
我也希望 versionName 自动增加。所以这只是对 CommonsWare 的回答的补充,它对我来说非常有用。这对我有用
defaultConfig {
versionCode code
versionName "1.1." + code
minSdkVersion 14
targetSdkVersion 18
}
EDIT:
编辑:
As I am a bit lazy I want my versioning to work as automatically as possible. What I want is to have a Build Versionthat increases with each build, while the Version Numberand Version Nameonly increases when I make a release build.
由于我有点懒惰,我希望我的版本控制尽可能自动地工作。我想要的是有一个随每次构建而增加的构建版本,而版本号和版本名称仅在我进行发布构建时增加。
This is what I have been using for the past year, the basics are from CommonsWare's answer and my previous answer, plus some more. This results in the following versioning:
这是我过去一年一直在使用的内容,基础知识来自 CommonsWare 的答案和我之前的答案,以及更多内容。这导致以下版本控制:
Version Name: 1.0.5 (123)--> Major.Minor.Patch (Build), Major and Minor are changed manually.
版本名称:1.0.5 (123)--> Major.Minor.Patch (Build),Major 和 Minor 手动更改。
In build.gradle:
在 build.gradle 中:
...
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def value = 0
def runTasks = gradle.startParameter.taskNames
if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
value = 1;
}
def versionMajor = 1
def versionMinor = 0
def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
versionProps['VERSION_PATCH'] = versionPatch.toString()
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps['VERSION_NUMBER'] = versionNumber.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode versionNumber
versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild}) Release"
minSdkVersion 14
targetSdkVersion 23
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def fileNaming = "apk/RELEASES"
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
output.outputFile = new File(getProject().getRootDir(), "${fileNaming}-${versionMajor}.${versionMinor}.${versionPatch}-${outputFile.name}")
}
}
}
}
} else {
throw new GradleException("Could not read version.properties!")
}
...
}
...
Patch and versionCode is increased if you assemble your project through the terminal with 'assemble', 'assembleRelease'or 'aR'which creates a new folder in your project root called apk/RELEASE so you don't have to look through build/outputs/more/more/more to find your apk.
如果您使用'assemble'、'assembleRelease'或'aR'通过终端组装项目,则补丁和版本代码会增加,这会在项目根目录中创建一个名为 apk/RELEASE 的新文件夹,因此您不必查看构建/输出/more/more/more 找到您的 apk。
Your version properties would need to look like this:
您的版本属性需要如下所示:
VERSION_NUMBER=1
VERSION_BUILD=645
VERSION_PATCH=1
Obviously start with 0. :)
显然是从 0 开始的。:)
回答by Paul Cantrell
A slightly tightened-up version of CommonsWare's excellent answer creates the version file if it doesn't exist:
如果版本文件不存在,CommonsWare 的优秀答案的稍微收紧的版本会创建版本文件:
def Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if(versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode code
versionName "1.1"
minSdkVersion 14
targetSdkVersion 18
}
回答by emmby
I looked at a few options to do this, and ultimately decided it was simpler to just use the current time for the versionCode instead of trying to automatically increment the versionCode and check it into my revision control system.
我查看了几个选项来执行此操作,最终决定只使用当前时间作为 versionCode,而不是尝试自动增加 versionCode 并将其签入我的修订控制系统更简单。
Add the following to your build.gradle
:
将以下内容添加到您的build.gradle
:
/**
* Use the number of seconds/10 since Jan 1 2016 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
def vcode = (int)(((new Date().getTime()/1000) - 1451606400) / 10)
android {
defaultConfig {
...
versionCode vcode
}
}
However, if you expect to upload builds beyond year 2696, you may want to use a different solution.
但是,如果您希望上传 2696 年以后的版本,您可能需要使用不同的解决方案。
回答by C0D3LIC1OU5
Another way of getting a versionCode
automatically is setting versionCode
to the number of commits in the checked out git
branch. It accomplishes following objectives:
另一种versionCode
自动获取 a 的方法是设置versionCode
签出git
分支中的提交次数。它实现了以下目标:
versionCode
is generated automatically and consistently on any machine (including aContinuous Integration
and/orContinuous Deployment
server).- App with this
versionCode
is submittable to GooglePlay. - Doesn't rely on any files outside of repo.
- Doesn't push anything to the repo
- Can be manually overridden, if needed
versionCode
在任何机器(包括Continuous Integration
和/或Continuous Deployment
服务器)上自动且一致地生成。- 具有此
versionCode
功能的应用可提交至 GooglePlay。 - 不依赖于 repo 之外的任何文件。
- 不会将任何内容推送到 repo
- 如果需要,可以手动覆盖
Using gradle-gitlibrary to accomplish the above objectives. Add code below to your build.gradle
file the /app
directory:
使用gradle-git库来完成上述目标。将以下代码添加到您的build.gradle
文件/app
目录中:
import org.ajoberstar.grgit.Grgit
repositories {
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.ajoberstar:grgit:1.5.0'
}
}
android {
/*
if you need a build with a custom version, just add it here, but don't commit to repo,
unless you'd like to disable versionCode to be the number of commits in the current branch.
ex. project.ext.set("versionCodeManualOverride", 123)
*/
project.ext.set("versionCodeManualOverride", null)
defaultConfig {
versionCode getCustomVersionCode()
}
}
def getCustomVersionCode() {
if (project.versionCodeManualOverride != null) {
return project.versionCodeManualOverride
}
// current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
// above.
ext.repo = Grgit.open(project.file('..'))
// should result in the same value as running
// git rev-list <checked out branch name> | wc -l
def numOfCommits = ext.repo.log().size()
return numOfCommits
}
NOTE: For this method to work, it's best to only deploy to Google Play Store from the same branch (ex. master
).
注意:要使此方法起作用,最好仅从同一分支(例如master
)部署到 Google Play 商店。
回答by moallemi
Recently I was working on a gradle plugin for Android that makes generating versionCodeand versionNameautomatically. there are lots of customization. here you can find more info about it https://github.com/moallemi/gradle-advanced-build-version
最近我正在为 Android 开发一个 gradle 插件,它可以自动生成versionCode和versionName。有很多定制。在这里你可以找到更多关于它的信息 https://github.com/moallemi/gradle-advanced-build-version
回答by carvaq
Another option, for incrementing the versionCode
and the versionName
, is using a timestamp.
另一种用于增加versionCode
和 的选项versionName
是使用时间戳。
defaultConfig {
versionName "${getVersionNameTimestamp()}"
versionCode getVersionCodeTimestamp()
}
def getVersionNameTimestamp() {
return new Date().format('yy.MM.ddHHmm')
}
def getVersionCodeTimestamp() {
def date = new Date()
def formattedDate = date.format('yyMMddHHmm')
def code = formattedDate.toInteger()
println sprintf("VersionCode: %d", code)
return code
}
Starting on January,1 2022 formattedDate = date.format('yyMMddHHmm') exceeds the capacity of Integers
从 2022 年 1 月 1 日开始 formattedDate = date.format('yyMMddHHmm') 超出了整数的容量
回答by NickUnuchek
To increment versionCode only in release version do it:
要仅在发布版本中增加 versionCode,请执行以下操作:
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
def versionPropsFile = file('version.properties')
def code = 1;
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
List<String> runTasks = gradle.startParameter.getTaskNames();
def value = 0
for (String item : runTasks)
if ( item.contains("assembleRelease")) {
value = 1;
}
code = Integer.parseInt(versionProps['VERSION_CODE']).intValue() + value
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
}
else {
throw new GradleException("Could not read version.properties!")
}
defaultConfig {
applicationId "com.pack"
minSdkVersion 14
targetSdkVersion 21
versionName "1.0."+ code
versionCode code
}
expects an existing c://YourProject/app/version.properties
file, which you would create by hand before the first build to have VERSION_CODE=8
需要一个现有c://YourProject/app/version.properties
文件,您将在第一次构建之前手动创建该文件VERSION_CODE=8
File
version.properties
:
文件
version.properties
:
VERSION_CODE=8
VERSION_CODE=8
回答by Ahmad Aghazadeh
Create file version.properties
创建文件 version.properties
MAJOR=1
MINOR=3
PATCH=6
VERSION_CODE=1
Change build.gradle
:
改变build.gradle
:
android {
def _versionCode=0
def _major=0
def _minor=0
def _patch=0
def _applicationId = "com.example.test"
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
_patch = versionProps['PATCH'].toInteger() + 1
_major = versionProps['MAJOR'].toInteger()
_minor = versionProps['MINOR'].toInteger()
_versionCode= versionProps['VERSION_CODE'].toInteger()+1
if(_patch==99)
{
_patch=0
_minor=_minor+1
}
if(_major==99){
_major=0
_major=_major+1
}
versionProps['MAJOR']=_major.toString()
versionProps['MINOR']=_minor.toString()
versionProps['PATCH']=_patch.toString()
versionProps['VERSION_CODE']=_versionCode.toString()
versionProps.store(versionPropsFile.newWriter(), null)
}
else {
throw new GradleException("Could not read version.properties!")
}
def _versionName = "${_major}.${_versionCode}.${_minor}.${_patch}"
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId _applicationId
minSdkVersion 11
targetSdkVersion 23
versionCode _versionCode
versionName _versionName
}
}
}
Output : 1.1.3.6
输出 : 1.1.3.6
回答by Sergey Shustikov
Define versionNamein AndroidManifest.xml
定义的versionName在AndroidManifest.xml
android:versionName="5.1.5"
Inside android{...}
block in build.gradle
of app level :
应用程序级别的内部android{...}
块build.gradle
:
defaultConfig {
applicationId "com.example.autoincrement"
minSdkVersion 18
targetSdkVersion 23
multiDexEnabled true
def version = getIncrementationVersionName()
versionName version
}
Outside android{...}
block in build.gradle
of app level :
应用程序级别的外部android{...}
块build.gradle
:
def getIncrementedVersionName() {
List<String> runTasks = gradle.startParameter.getTaskNames();
//find version name in manifest
def manifestFile = file('src/main/AndroidManifest.xml')
def matcher = Pattern.compile('versionName=\"(\d+)\.(\d+)\.(\d+)\"').matcher(manifestFile.getText())
matcher.find()
//extract versionName parts
def firstPart = Integer.parseInt(matcher.group(1))
def secondPart = Integer.parseInt(matcher.group(2))
def thirdPart = Integer.parseInt(matcher.group(3))
//check is runTask release or not
// if release - increment version
for (String item : runTasks) {
if (item.contains("assemble") && item.contains("Release")) {
thirdPart++
if (thirdPart == 10) {
thirdPart = 0;
secondPart++
if (secondPart == 10) {
secondPart = 0;
firstPart++
}
}
}
}
def versionName = firstPart + "." + secondPart + "." + thirdPart
// update manifest
def manifestContent = matcher.replaceAll('versionName=\"' + versionName + '\"')
manifestFile.write(manifestContent)
println "incrementVersionName = " + versionName
return versionName
}
After create singed APK :
创建烧焦的 APK 后:
android:versionName="5.1.6"
Note : If your versionNamedifferent from my, you need change regexand extract parts logic.
注意:如果您的versionName与我的不同,则需要更改正则表达式并提取部分逻辑。