使用Git和Eclipse为您的Android应用程序编号的自动版本

时间:2013-02-15 12:51:47

标签: android git versioning

我相信计算机是做重复性任务的最佳选择。我当然不是,我要么忘记,要么(大多数时候)不以一致的方式做事 - 这不是我想要的。

我可能要做的一件事是在发布新版Android应用时忘记清单中的版本信息。在过去,我使用过具有自动版本编号功能的已配置构建系统,并且我已经习惯了(或者我可能很懒)。

我发现这个Stackoverflow post在提出解决方案时非常有用,但我花了一段时间对其进行微调,以便它能够按照我想要的方式工作。早期的尝试有时会导致继续建设,这是一个痛苦。所以我想我会在这里发布我的解决方案,希望别人能发现它有用。

4 个答案:

答案 0 :(得分:14)

此解决方案是在Linux上开发的。我确信熟练的Windows& Mac开发人员可以将其适应他们的平台,但我不是这样的开发人员。 Linux是我的技能所在。

Git在git describe --dirty命令中有一个很好的功能。它会向下扫描提交日志并找到标记,然后从那里构建一个版本字符串。如果这是一个“生产构建”,其中最后一次提交已被标记,并且所有文件都已签入,那么这就是您的版本字符串。如果这是一个开发版本,那么最后一个标记附加了额外提交的数量和缩写的哈希码。 --dirty标志只是锦上添花的结果:如果尚未提交任何已修改的文件,它会附加单词dirty。这非常适合清单文件中的android:versionName属性。

对于android:versionCode,需要一个号码。这需要为发布而不是开发构建计时,并且因为每个发行版都有一个带有版本字符串的标记,我只需要计算这些。我始终以v<major>.<minor>[.<patch>]格式标记我的版本,其中<major><minor><patch>只是数字。因此计算以小写“v”开头,后跟数字的计数标记就是这里真正需要的。

在跟踪模板清单文件后,我发现最好的方法是在项目库中使用AndroidManifest.xml文件,使用流编辑器sed进行编辑,并将结果存入bin / AndroidManifest.xml

所以我开发了下面的脚本,将它放在与我的项目相同级别的脚本文件夹中(以便它们可以共享相同的脚本),然后在Eclipse中配置自定义构建器。

有一个我称之为version.sh的脚本:

#/bin/bash

echo "Auto Version: `pwd`"

CODE=`git tag | grep -c ^v[0-9]`
NAME=`git describe --dirty | sed -e 's/^v//'`
COMMITS=`echo ${NAME} | sed -e 's/[0-9\.]*//'`

if [ "x${COMMITS}x" = "xx" ] ; then
    VERSION="${NAME}"
else
    BRANCH=" (`git branch | grep "^\*" | sed -e 's/^..//'`)"
    VERSION="${NAME}${BRANCH}"
fi

echo "   Code: ${CODE}"
echo "   Ver:  ${VERSION}"

cat AndroidManifest.xml | \
    sed -e "s/android:versionCode=\"[0-9][0-9]*\"/android:versionCode=\"${CODE}\"/" \
        -e "s/android:versionName=\".*\"/android:versionName=\"${VERSION}\"/" \
    > bin/AndroidManifest.xml

exit 0

要在此处配置构建器,请执行以下步骤:

1)。右键单击项目库并选择“属性”,然后选择“构建器”。

2)。点击“新建”按钮,然后选择“程序”选项。

3)。将您的版本命名为“&lt; project&gt; Auto Version”。这个字符串在所有项目中都必须是唯一的。

4)。按如下方式配置“Main”选项卡:

4A)。在“位置”部分中,使用“浏览文件系统”并导航并选择脚本文件。

4B)。在“工作目录”部分中,使用“浏览工作区”选择项目。

5)。在“刷新”选项卡中取消选中“完成后刷新资源”。

6)。不要在“环境”选项卡中设置任何变量。

7)。在“构建选项”选项卡中:

7A)。确保勾选“手动构建期间”,并

7B)。 “自动构建期间”也会被勾选。

7C)。我现在还有其他一切未被选中。我甚至没有为它分配一个控制台。老鹰目瞪口呆可能已经发现脚本确实输出了一些信息,但现在我已经开始工作了,我只是希望这个东西能够安静地运行而不会打扰我。

8)。好的是构建设置,然后将构建器放在“Android Pre-Compile”和“Java Builder”之间。

返回开发应用程序,确保它们的版本正确,并查看应用程序的信息。不是那个版本号很酷。 : - )

史蒂夫

答案 1 :(得分:12)

Idea (使用ant和git可执行文件)

好的,这是一种新颖的方式:

  • 用于计算version.code

    git rev-list master --first-parent --count

    这跟随versioning guideline。因为它有效地从初始提交(包括)中找到提交的数量,该提交总是从先前版本递增。

  • 用于计算version.name

    git describe --tags --dirty --abbrev=7

实现:

build.xml通常会导入名为custom_rules.xml

的自定义ant脚本

所以将脚本的内容设为:

<?xml version="1.0" encoding="UTF-8"?>
<project name="application-custom">

<macrodef name="git" taskname="@{taskname}">
    <attribute name="command" />
    <attribute name="dir" default="" />
    <attribute name="property" default="" />
    <attribute name="taskname" default="" />
    <attribute name="failonerror" default="on" />
    <element name="args" optional="true" />
    <sequential>
        <exec executable="git" dir="@{dir}" outputproperty="@{property}" 
            failifexecutionfails="@{failonerror}" failonerror="@{failonerror}">
            <arg value="@{command}" />
            <args/>
        </exec>
    </sequential>
</macrodef>

<target name="-pre-build">
    <git command="rev-list" property="versioning.code" taskname="versioning">
        <args>
            <arg value="master" />
            <arg value="--first-parent" />
            <arg value="--count" />
        </args>
    </git>
    <git command="describe" property="versioning.name" taskname="versioning">
        <args>
            <arg value="--tags" />
            <arg value="--dirty" />
            <arg value="--abbrev=7" />
        </args>
    </git>
    <echo level="info" taskname="versioning">${versioning.code}, ${versioning.name}</echo>
    <replaceregexp file="AndroidManifest.xml" match='android:versionCode=".*"' replace='android:versionCode="${versioning.code}"' />
    <replaceregexp file="AndroidManifest.xml" match='android:versionName=".*"' replace='android:versionName="${versioning.name}"' />
</target>

<target name="-post-build" >
    <replaceregexp file="AndroidManifest.xml" match='android:versionCode=".*"' replace='android:versionCode="0"' />
    <replaceregexp file="AndroidManifest.xml" match='android:versionName=".*"' replace='android:versionName="0"' />
</target>

就是这么做的。

在坚果shell中,它只是用当前版本代码和名称替换android.versionCodeandroid.versionName,存储在git中。

注意事项

  • 初始版本代码和名称在构建完成时设置为0。如果你需要它,替换-post-build目标中的零,或者(尽管我非常怀疑你会需要它)你可以将它配置为一些属性(文件或嵌入式;你的选择)
  • 如果构建失败或中止,版本将保持原样。 (虽然我非常怀疑它是否有任何问题,只需还原文件!)

享受。

参考文献

重要编辑

  1. 阻止使用HEAD计算内部版本号;在开发期间进行构建时以及稍后在安装稳定版本时(或者在进行主要版本转换的测试时)导致版本降级问题。使用master(或用于生产构建的分支)ref代替。
  2. PS:与AS用户相关:Automatically versioning Android project from git describe with Android Studio/Gradle

答案 2 :(得分:8)

使用Android Studio(Gradle):

android {
    defaultConfig {
        ...
        // Fetch the version according to git latest tag and "how far are we from last tag"
        def longVersionName = "git -C ${rootDir} describe --tags --long".execute().text.trim()
        def (fullVersionTag, versionBuild, gitSha) = longVersionName.tokenize('-')
        def(versionMajor, versionMinor, versionPatch) = fullVersionTag.tokenize('.')

        // Set the version name
        versionName "$versionMajor.$versionMinor.$versionPatch($versionBuild)"

        // Turn the version name into a version code
        versionCode versionMajor.toInteger() * 100000 +
                versionMinor.toInteger() * 10000 +
                versionPatch.toInteger() * 1000 +
                versionBuild.toInteger()

        // Friendly print the version output to the Gradle console
        printf("\n--------" + "VERSION DATA--------" + "\n" + "- CODE: " + versionCode + "\n" + 
               "- NAME: " + versionName + "\n----------------------------\n")
        ...
    }
}

答案 3 :(得分:0)

'  for windows
'   preBuildMy.cmd  include  repVer.vbs 

' repVer.vbs :

Dim objFileSystem, objOutputFile
Dim objInputFile
Dim sText,gitFile

FileName = "./bin/AndroidManifest.xml"
'  gitFile = ".\..\.git\refs\heads\master"
gitFile = ".\..\.git\refs\remotes\origin\master"

Set objFileSystem = CreateObject("Scripting.fileSystemObject")

set objInputFile= objFileSystem.OpenTextFile(FileName)
sText= objInputFile.ReadAll

set objOutputFile = objFileSystem.CreateTextFile(FileName , TRUE)

set objInputFile= objFileSystem.OpenTextFile(gitFile)
refText= objInputFile.ReadAll

sText = Replace(sText,"v1.0","v 1.0 " & Now & " ref=" & mid(refText,1,7))

objOutputFile.WriteLine(sText)

objOutputFile.Close

Set objFileSystem = Nothing
WScript.Quit(0)