在Android应用程序中自动增加版本代码

有没有一种方法来每次在Eclipse中构buildAndroid应用程序时自动递增版本代码?

根据http://developer.android.com/guide/publishing/versioning.html ,您必须在AndroidManifest.xml手动增加您的版本代码。

我明白,你必须在每个构build之前运行一个脚本,例如parsingAndroidManifest.xml文件,find版本号,增加它并在构build本身启动之前保存文件。 不过,我无法了解Eclipse是如何支持在构build之前/之后运行脚本的。

我已经find了关于configurationant生成器的这篇文章 ,但这不完全是关于Android,我担心这会混淆了Android的预定义的build设步骤?

应该是一个普遍的问题,你是怎么解决的?

那么可以手工做到这一点,但只要你忘记做这件事,你会得到不同的版本号码相同,整个版本没什么意义。

所以,我看到这样的:

根据你提供的文章,使用ant来完成这个任务(目标?)。

  1. parsingManifest(parsingXML)
  2. 得到旧版本的表单并增加它/从回购版本
  3. 在清单中存储新版本
  4. build立Android应用程序。

但即时通讯我的情况下,我通常填写这个字段的值基于标签的修订时,我部署或分发应用程序。

我完成了这个。 下面是我为下一个人做的(使用Eclipse):

1)创build一个外部控制台可执行文件,它将把一个新的版本代码写入到AndroidManifest.xml中:(我的是C#)

 using System.IO; using System.Text.RegularExpressions; namespace AndroidAutoIncrementVersionCode { class Program { static void Main(string[] args) { try { string FILE = @"AndroidManifest.xml"; string text = File.ReadAllText(FILE); Regex regex = new Regex(@"(?<A>android:versionCode="")(?<VER>\d+)(?<B>"")", RegexOptions.IgnoreCase); Match match = regex.Match(text); int verCode = int.Parse(match.Groups["VER"].Value) + 1; string newText = regex.Replace(text, "${A}" + verCode + "${B}", 1); File.WriteAllText(FILE, newText); } catch { } } } } 

除此之外:任何C-sharp编译器都可以构build这个应用程序,您不需要Visual Studio甚至Windows

  1. 如果你没有它,安装.NET运行时( Mono将工作,链接 )( 链接到MS的.NET框架2.0,2.0是最小的下载,任何版本> = 2.0是好的 )
  2. 将此代码复制到一个*.cs文件(我命名为: AndroidAutoIncrementVersionCode.cs
  3. 打开命令提示符并导航到您创build*.cs文件的位置
  4. 使用这个命令build立文件(在Windows上,类似于Mono,但改变编译器的path): c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc AndroidAutoIncrementVersionCode.cs (更多信息请参见.NET或Mono )
  5. 恭喜,你只是build立了一个没有任何工具的C#应用​​程序,它应该已经在同一个目录下自动生成了AndroidAutoIncrementVersionCode.exe

    **里程可能会有所不同,path可能会不同,无需购买,在禁止的情况下无效,因为C#太棒了,而且人们错误地认为它有MSlocking,所以您可以轻松地将其转换成另一种语言(但我不打算为你做这件事)。 顺便说一句,任何.NET编译器的任何版本都可以工作,我调整了最小公分母的代码… *

抛开一边

2)在构build过程中运行可执行文件:a)转到项目属性

去项目属性

b)在属性中,转到“build造者” – >“新build…”

Eclipse属性屏幕

c)select“程序”

选择程序

d)在“主”选项卡中select程序位置(我也设置工作目录是安全的),并给它一个名字,如果你愿意。

编辑配置 - 主

e)在“刷新”选项卡中,select“完成后刷新资源”和“所选资源”选项 – 这将在我们编写清单后刷新清单。

编辑配置 - 刷新

f)在“构build选项”选项卡中,您可以closures“分配控制台”,因为您没有input和输出,然后只select“手动构build期间”和“自动构build期间”,如果选中“取消清理”,则取消select。 然后select“指定一组工作的相关资源”并点击“指定资源…”button。 在“编辑工作集”对话框中,find对话框中的“AndroidManifest.xml”文件,并检查它,然后点击“完成”

编辑配置 - 编译选项编辑工作集

f)现在点击“编辑configuration对话框”中的“确定”,在您的应用程序的属性中,select新创build的构build器,并保持点击“向上”,直到它在列表的顶部,这样自动增量运行首先,不会触发意外的不同步状态或重build。 一旦你build立的新build筑师在列表顶部,点击“确定”,你就完成了。

编辑配置 - 点击确定在这里输入图像说明

这个适用于* nix系统的shell脚本将版本代码的versionCode和最后一个组件设置为当前的subversion版本。 我正在使用NetBeans和NBAndroid,我从custom_rules.xml中的目标-pre-compile中调用这个脚本。

将该脚本保存在与AndroidManifest.xml相同的目录中的一个名为incVersion的文件中,使其可执行: chmod +x incVersion

 manf=AndroidManifest.xml newverfull=`svnversion` newvers=`echo $newverfull | sed 's/[^0-9].*$//'` vers=`sed -n '/versionCode=/s/.*"\([0-9][0-9]*\)".*/\1/p' $manf` vername=`sed -n '/versionName=/s/.*"\([^"]*\)".*/\1/p' $manf` verbase=`echo $vername | sed 's/\(.*\.\)\([0-9][0-9]*\).*$/\1/'` newvername=$verbase$newverfull sed /versionCode=/s/'"'$vers'"'/'"'$newvers'"'/ $manf | sed /versionName=/s/'"'$vername'"'/'"'$newvername'"'/ >new$manf && cp new$manf $manf && rm -f new$manf echo versionCode=$newvers versionName=$newvername 

创build或编辑custom_rules.xml并添加:

 <?xml version="1.0" encoding="UTF-8"?> <project name="custom_rules"> <xmlproperty file="AndroidManifest.xml" prefix="mymanifest" collapseAttributes="true"/> <target name="-pre-compile"> <exec executable="./incVersion" failonerror="true"/> </target> </project> 

所以如果我当前的svn修订版本是82,我最终在AndroidManifest.xml中看到:

 android:versionCode="82" android:versionName="2.1.82"> 

当我想发布一个新版本的时候,我通常会更新versionName的第一部分,但是即使我忘记了,versionName的最后一部分(在我的About活动中公开)也会告诉我它是从哪个svn修订版本。 另外,如果我没有检查更改,版本号将是82M,versionName将是2.1.82M。

每次构build完成时,简单地增加版本号的优点是数量保持在控制之下,并且可以直接与特定的svn修订版相关。 在调查最新版本以外的错误时非常有帮助。

FWIW,我能够在六行python中更新构build版本值:

 #!/bin/env python import os from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") dom1.documentElement.setAttribute("android:versionName","%build.number%") f = os.open("AndroidManifest.xml", os.O_RDWR) os.write( f, dom1.toxml() ) 

基于Charles的回答 ,以下增加了现有的构build版本:

 #!/usr/bin/python from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") oldVersion = dom1.documentElement.getAttribute("android:versionName") versionNumbers = oldVersion.split('.') versionNumbers[-1] = unicode(int(versionNumbers[-1]) + 1) dom1.documentElement.setAttribute("android:versionName", u'.'.join(versionNumbers)) with open("AndroidManifest.xml", 'wb') as f: for line in dom1.toxml("utf-8"): f.write(line) 

Receipe:

要在AndroidManifest.xml中自动将AndroidManifest.xml中的manifest元素的android:versionCode属性设置为每次运行构build时的当前时间(从以秒为单位的纪元),将其添加到custom_rules.xml中的-pre-build目标Android文件。

 <target name="-pre-build"> <exec executable="date" outputproperty="CURRENT_TIMESTAMP"> <arg value="+%s"/> </exec> <replaceregex file="AndroidMainfest.xml" match="android:versionCode=.*" replace='android:versionCode="${CURRENT_TIMESTAMP}"' /> </target> 

确认testing

从Android项目目录中使用以下shell命令获取生成的apk文件的versionCode属性:

 $ANDROID_SDK/build-tools/20.0.0/aapt dump badging bin/<YourProjectName>.apk | grep versionCode 

并将其与从shell命令返回的当前date进行比较: date +%s差异应该等于上述两个确认步骤之间的时间段(以秒为单位)。

这种方法的优点:

  1. 无论构build是从命令行还是Eclipse启动,都会更新versionCode。
  2. versionCode保证是唯一的,每个构build都在增加
  3. 如果你需要的话,versionCode可以被反编译成一个近似的编译时间
  4. 上面的脚本replace了versionCode的任何当前值,甚至不需要macros占位符(例如-build_id-)。
  5. 由于AndroidManifest.xml文件中的值已更新,因此可以将其检入到版本控制中,并保留实际值,而不是某些macros(如-build_id-)。

build立在Rocky的答案我增强了这个Python脚本有点增加versionCode,在Eclipse上工作(根据ckozl伟大的教程集成)和Mac OSX

 #!/usr/bin/python from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") oldVersion = dom1.documentElement.getAttribute("android:versionName") oldVersionCode = dom1.documentElement.getAttribute("android:versionCode") versionNumbers = oldVersion.split('.') versionNumbers[-1] = unicode(int(versionNumbers[-1]) + 1) dom1.documentElement.setAttribute("android:versionName", u'.'.join(versionNumbers)) dom1.documentElement.setAttribute("android:versionCode", str(int(oldVersionCode)+1)) with open("AndroidManifest.xml", 'wb') as f: for line in dom1.toxml("utf-8"): f.write(line) 

也不要忘了chmod +x autoincrement.py ,并确保你有正确的pathpython第一行(取决于你的环境) sulai指出

我做了类似的事情,但是把它写成了一个桌面AIR应用程序,而不是一些外部的C#(没有感觉安装另一个构build系统)。 构build此Flex / ActionScript应用程序并更改文件的path,将其构build为独立的桌面应用程序。 它重写了你的文件的1.2.3部分。

  <?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="371" height="255" applicationComplete="Init();"> <fx:Declarations> <!-- Place non-visual elements (eg, services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ public function Init():void { import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; var myFile:File = new File("D:\\Dropbox\\Projects\\My App\\src\\Main-app.xml"); var fileStream:FileStream = new FileStream(); fileStream.open(myFile, FileMode.READ); var fileContents:String = fileStream.readUTFBytes(fileStream.bytesAvailable); var startIndex:Number = fileContents.indexOf("<versionNumber>"); var numberIndex:Number = startIndex + 15; var endIndex:Number = fileContents.indexOf("</versionNumber>"); if (startIndex == -1 || endIndex == -1) return; var versionNumber:String = fileContents.substr(numberIndex, endIndex - numberIndex); var versionArr:Array = versionNumber.split("."); var newSub:Number = Number(versionArr[2]); newSub++; versionArr[2] = newSub.toString(); versionNumber = versionArr.join("."); var newContents:String = fileContents.substr(0, startIndex) + "<versionNumber>" + versionNumber + "</versionNumber>" + fileContents.substr(endIndex + 16); fileStream.close(); fileStream = new FileStream(); fileStream.open(myFile, FileMode.WRITE); fileStream.writeUTFBytes(newContents); fileStream.close(); close(); } ]]> </fx:Script> <s:Label x="10" y="116" width="351" height="20" fontSize="17" text="Updating My App Version Number" textAlign="center"/> </s:WindowedApplication> 

我能够根据所提供的信息制定出我自己的解决scheme。 如果对某人有用,这里是我的bash脚本,用于在Linux上使用GIT VCS时更新versionCode和versionName属性。

编辑AndroidManifest.xml文件的脚本如下所示:

 #/bin/bash CODE=`git tag | grep -c ^v` NAME=`git describe --dirty` COMMITS=`echo ${NAME} | sed -e 's/v[0-9\.]*//'` if [ "x${COMMITS}x" = "xx" ] ; then VERSION="${NAME}" else BRANCH=" (`git branch | grep "^\*" | sed -e 's/^..//'`)" VERSION="${NAME}${BRANCH}" fi cat AndroidManifest.template.xml \\ | sed -e "s/__CODE__/${CODE}/" \\ -e "s/__VERSION__/${VERSION}/" > AndroidManifest.xml exit 0 

它parsing模板文件(AndroidManifest.template.xml),并用更合适的值replacestring“__VERSION__”和“__CODE__”:

  • “__CODE__”被replace为Git仓库中以单个小写字母V开头的标签数,然后是数字和点序列。 这看起来像大多数版本string,如:“v0.5”,“v1.1.4”等。
  • “__VERSION__”被replace为来自“git describe”命令的输出的组合,如果不是“干净”的构build,则构build它的分支。

通过“干净的”构build我的意思是所有的组件都在版本控制下,他们是最新的提交标记。 “git describe –dirty”将根据当前分支上最近一次提交的最后一个可到达注释标签报告一个版本号。 如果自该标记以来有提交,那么提交这些提交的计数就像上次提交的缩写对象名称一样。 如果修改了版本控制下的任何文件,则“–dirty”选项将在上述信息中附加“-dirty”。

所以AndroidManifest.xml不再受版本控制,你只能编辑AndroidManifest.template.xml文件。 你的AndroidManifest.template.xml文件的开始看起来像这样:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.packagename" android:versionCode="__CODE__" android:versionName="__VERSION__" > 

希望这对某人有用

所有功劳都归ckoz所有,但是我用c#写了自己的实现。 我认为这是一个更快一点,不吃错误,因为如果出现问题可能是错误的configuration,我应该知道。

 namespace AndroidVersionCodeAutoIncrement { using System.IO; using System.Text.RegularExpressions; public class Program { private static readonly Regex VersionCodeRegex = new Regex("android:versionCode=\"(?<version>.*)\"", RegexOptions.Compiled); public static void Main() { using (var manifestFileStream = File.Open("AndroidManifest.xml", FileMode.Open, FileAccess.ReadWrite)) using (var streamReader = new StreamReader(manifestFileStream)) { var manifestFileText = streamReader.ReadToEnd(); var firstMatch = VersionCodeRegex.Match(manifestFileText); if (firstMatch.Success) { int versionCode; var versionCodeValue = firstMatch.Groups["version"].Value; if (int.TryParse(versionCodeValue, out versionCode)) { manifestFileText = VersionCodeRegex.Replace(manifestFileText, "android:versionCode=\"" + (versionCode + 1) + "\"", 1); using (var streamWriter = new StreamWriter(manifestFileStream)) { manifestFileStream.Seek(0, SeekOrigin.Begin); streamWriter.Write(manifestFileText); manifestFileStream.SetLength(manifestFileText.Length); } } } } } } } 

对于那些在OSX上想要使用Python的人,但是不能松散的当XMLparsing器完成parsing的XML格式的时候,这里是一个python脚本,它会根据正则expression式来进行增量操作,格式是:

 #!/usr/bin/python import re f = open('AndroidManifest.xml', 'r+') text = f.read() result = re.search(r'(?P<groupA>android:versionName=")(?P<version>.*)(?P<groupB>")',text) version = str(float(result.group("version")) + 0.01) newVersionString = result.group("groupA") + version + result.group("groupB") newText = re.sub(r'android:versionName=".*"', newVersionString, text); f.seek(0) f.write(newText) f.truncate() f.close() 

代码基于@ckozl答案,只是在python中完成,所以你不需要为此创build一个可执行文件。 只需将脚本命名为autoincrement.py,将其放置在与manifest.xml文件相同的文件夹中,然后执行ckozl上面描述的步骤!

如果你想更新AndroidManifest.xml来使用特定的版本号,也许从一个构build系统,那么你可以使用我刚推送到GitHub的项目: https : //github.com/bluebirdtech/AndroidManifestVersioner

这是一个基本的.NET命令行应用程序,用法:

 AndroidManifestVersioner <path> <versionCode> <versionName>. 

感谢其他海报的代码。

这是Java版本的价值。 还处理多个清单。

 String directory = "d:\\Android\\workspace\\"; String[] manifests = new String[] { "app-free\\AndroidManifest.xml", "app-donate\\AndroidManifest.xml", }; public static void main(String[] args) { new version_code().run(); } public void run() { int I = manifests.length; for(int i = 0; i < I; i++) { String path = directory + manifests[i]; String content = readFile(path); Pattern versionPattern = Pattern.compile( "(.*android:versionCode=\")([0-9]+)(\".*)", Pattern.DOTALL ); Matcher m = versionPattern.matcher(content); if (m.matches()) { int code = Integer.parseInt( m.group(2) ) + 1; System.out.println("Updating manifest " + path + " with versionCode=" + code); String newContent = m.replaceFirst("$1" + code + "$3"); writeFile(path + ".original.txt", content); writeFile(path, newContent); } else { System.out.println("No match to update manifest " + path); } } } 

如果你使用gradle,那么你可以在build.gradle使用特定的versionNameversionCode 。 你可以使用git commit count作为一个越来越多的数字来识别构build。

你也可以使用这个库: https : //github.com/rockerhieu/Versionberg 。