如何在Eclipse中自动增加Android项目的内部版本号(更喜欢便携式解决方案)

时间:2012-05-25 19:05:23

标签: android eclipse

让IDE自动增加内部版本号是一个长期讨论的问题 - 我总是感到惊讶的是,对我来说似乎非常基本的东西是如此多的工作。

本主题的得分最高的问答(相当多)在这里: https://stackoverflow.com/a/8156809/150016 我的问题是解决方案依赖于.net,我宁愿避免使用Eclipse解决方案的.net依赖。我还想避免对VCS的任何依赖。

所以,我正在寻找可移植的解决方案和'Eclipse-ish'。我认为最好的候选者是Ant解决方案(我将发布)或类似于上面链接答案中的dotNet应用程序的Java应用程序。

(我没有添加我对这个问题的答案,因为它有一个已接受的答案,并且已经是一个很长的帖子。如果主持人更喜欢我会删除这个问题,并将我的答案添加到上面的问题。)

我希望有一些相对简单的东西,但我认为解决这个问题的方法并不简单。

6 个答案:

答案 0 :(得分:8)

在项目的属性对话框中,在构建器下,您可以配置脚本以在构建apk之前运行。

在属性对话框中,从左侧列表中选择“构建器”。单击“新建”以添加新脚本。在弹出的对话框中,选择“程序”。在随后的对话框中,在“名称”字段中调用您喜欢的构建器程序。将路径放在“位置”字段中。在工作目录字段中为其指定一个工作目录。请注意,您可以在这些字段中指定变量(例如,我们使用${build_project:/libs/update_version.sh}来引用项目的lib目录中的脚本)。

您希望它在任何其他构建器之前运行,因此使用向上按钮将其移动到列表顶部。

在Dialog的Build Options选项卡上(它位于顶部的Name字段下方),您可以选择希望此程序运行的选项。

我在这里假设像Linux,Unix或MacOS这样的东西。在这些系统中,您可以使用grep或其变体来获取当前的versionCode,增加它,然后使用awk或类似来相应地修改文件。或者,您可以编写Ruby,Python,Perl等脚本来替换AndroidManifest.xml文件中的versionCode。我想在Windows上有相同的工具,但我对这个环境并不是很熟悉。

答案 1 :(得分:7)

你有没有尝试'Maven-ise'你的android项目构建?

如果您使用"maven-android-plugin",则可以使用pom.xml的“version”标记跟踪项目构建。

在pom.xml中,您可以使用"versions-maven-plugin"

增加构建版本

要将增加的内部版本号反映到AndroidManifest.xml,您可以使用pom文件中的Synchronizing Version technique

这样,每次应用程序构建时,您都可以通过运行“versions-maven-plugin”来自动增加android项目内部版本号。该解决方案也可以与Ant解决方案相同的方式移植。

我希望这也可以解决你提到的问题(以及我所理解的)。如果缺少某些东西,请纠正我。

答案 2 :(得分:3)

这是一个使用Ant的解决方案。我必须承认,获取Ant设置有点麻烦,但它似乎是Eclipse的一个广泛使用和强大的附件,所以我相信它会在其他方面对我有价值。

Ant是构建没有Eclipse的Android SDK应用程序(如described here)的首选解决方案,但不是ADT的一部分,所以如果你刚刚使用Eclipse,你可能不会拥有它。

因此,第一步是下载并安装Ant from here

接下来将Ant添加到您的路径中,并确保您的路径也指向JDK(而不是JRE)。在Windows上,我发现我还必须创建JAVA_HOME并将其指向JDK的根目录。

我们只需要Ant用于自动增量步骤 - 目的不是替换Eclipse并将其用于整个构建 - 但是在这个方向上做一些步骤以确保Ant正常工作是很有用的。因此,转到项目的根目录并键入

> android update project --path .

这将为您的项目创建一个build.xml。一旦我做完了,我就能做到了

> ant release

和Ant构建了我的项目。如果你想继续朝这个方向前进,我发现this article很有用。

接下来,我编辑了我的项目的新build.xml并添加了以下任务(它可以去任何地方,只是不在另一个任务/目标的中间)

 <target name="update.buildnum">
      <buildnumber/>
      <!-- this task creates (and increments) Ant property 'build.number' which I use below -->
      <echo>Current build number:${build.number}</echo>         
      <echoxml file="res/values/buildnum.xml">
                <resources>
                    <string name="buildnum">${build.number}</string>
                </resources>                    
      </echoxml>
 </target>

上面使用的任务会自动增加项目根目录中名为“build.number”的文件(它将创建)中的内部版本号。上面的任务的其余部分将当前构建号放入资源字符串中,以便您的应用程序可以使用以下代码检索它:

String build = context.getString( com.your.app.R.string. buildnum );
int appBuild = ( int ) Integer.parseInt( build ); 

有些人更喜欢将构建号写入AndroidManifest.xml中的应用程序代码的解决方案。 Here is一个包含执行该任务的任务的答案,但它需要第三方Ant任务(xmltask),并且我有点犹豫是否有第三方任务修改我的清单(现​​在非常庞大)在每个构建。如果您决定使用该任务,那么获取内部版本号的相应Android代码将是:

String packageName = ctx.getPackageName();
PackageInfo pInfo = ctx.getPackageManager().getPackageInfo( packageName, 0);
int appVer = pInfo.versionCode;

最后,每次进行构建时都需要让Eclipse运行此Ant任务。

转到项目的属性,找到Builders,然后单击按钮添加新的Builder。这里有很多选项,但你只需要指定几个。

  • 通过设置名称:字段为构建器指定名称。
  • 选择构建文件:。我使用'浏览工作区'选项来选择它,然后用“$ {workspace_loc:/appname/build.xml}”填充字段
  • 从目标标签上的列表中选择目标。在我的情况下,我不得不删除'help'任务(上面生成的build.mxl中的默认任务),然后添加'build.number'任务。我建议您只为手动构建设置目标。

我将新的Builder移动到第一个构建步骤。

此解决方案的一个问题是,每次让Eclipse部署(运行)您的应用程序时,即使项目未更改,也会将其视为新的手动构建。因此,如果将应用程序部署到多个设备,则每个设备将具有不同的构建版本,并具有自己的构建版本号。有一点可以改善这个问题,谷歌表示未来的ADT将允许在一次操作中进行多次部署。

这个(上面)在Win7 32bit上使用Ant 1.8.4,Eclipse Indigo SR2(3.7.2),ADT 20 preview 2和SDK Tools 20进行了测试。

答案 3 :(得分:1)

我的解决方案基于使用Ant(不含XMLTask)

<property name="version.file" value="version.properties"/>
<property name="manifest.file" value="AndroidManifest.xml"/>
<!--build.slot: 0.1.2.3.4.5-->
<property name="build.slot" value="2"/>

<target name="all">
    <antcall target="increment.build"/>
    <antcall target="update.manifest"/>
</target>

<target name="increment.build">
    <propertyfile file="${version.file}">
        <entry key="build.no" type="int" default="0" operation="+" value="1" />
    </propertyfile>
</target>

<scriptdef name="setBuildNo" language="javascript">
    <attribute name="verName" />
    <attribute name="buildNo" />
    <attribute name="buildSlot" />
    <attribute name="property" />
    <![CDATA[
        var verNums = attributes.get("vername").split(".");
        var buildNo = attributes.get("buildno");
        var buildSlot = attributes.get("buildslot");
        if (!(buildSlot > 1 && buildSlot < 10))
            buildSlot = 2;
        var newVer = "";
        for (var i = 0; i < Math.min(verNums.length, buildSlot); i++)
            newVer += (verNums[i].trim() || "0") + ".";
        for (var i = verNums.length; i < buildSlot; i++)
            newVer += "0" + ".";
        project.setProperty(attributes.get("property"), newVer + buildNo);
    ]]>
</scriptdef>

<target name="debug">
    <setBuildNo verName="1" buildNo="999" property="a"/>
    <setBuildNo verName="2." buildNo="999" property="b"/>
    <setBuildNo verName="3.3" buildNo="999" property="c"/>
    <setBuildNo verName="4.4." buildNo="999" property="d"/>
    <setBuildNo verName="5.5.5" buildNo="999" property="e"/>
    <setBuildNo verName="6.6.6." buildNo="999" property="f"/>
    <setBuildNo verName="7.7.7.7" buildNo="999" property="g"/>

    <echo>1 =&gt; ${a}</echo>
    <echo>2. =&gt; ${b}</echo>
    <echo>3.3 =&gt; ${c}</echo>
    <echo>4.4. =&gt; ${d}</echo>
    <echo>5.5.5 =&gt; ${e}</echo>
    <echo>6.6.6. =&gt; ${f}</echo>
    <echo>7.7.7.7 =&gt; ${g}</echo>

</target>

<target name="update.manifest">

    <fail message="File not found: &quot;${manifest.file}&quot;" status="1">
        <condition>
            <not>
                <available file="${manifest.file}" />
            </not>
        </condition>
    </fail>

    <!-- Reads build version -->
    <loadproperties srcfile="${version.file}">
        <filterchain>
            <linecontains>
                <contains value="build.no="/>
            </linecontains>
        </filterchain>
    </loadproperties>

    <!-- Reads versionName from AndroidManifest -->
    <xmlproperty file="${manifest.file}" collapseAttributes="true"/>
    <fail unless="manifest.android:versionName" message="Attribute &quot;android:versionName&quot; undefined into &quot;${manifest.file}&quot;" status="1"/>
    <property name="version.name" value="${manifest.android:versionName}"/>

    <!-- Create a new version -->
    <setBuildNo verName="${version.name}" buildNo="${build.no}" buildSlot="${build.slot}" property="new.version.name"/>

    <!-- Replaces using regexp -->
    <replaceregexp
        file="${manifest.file}"
        match="android:versionName.*=.*&quot;.*${version.name}.*&quot;"
        replace="android:versionName=&quot;${new.version.name}&quot;"/>

    <!-- Replaces for check and generates a exception (if not found version) -->
    <replace
        file="${manifest.file}"
        token="android:versionName=&quot;${new.version.name}&quot;"
        value="android:versionName=&quot;${new.version.name}&quot;"
        failOnNoReplacements="true"/>

    <!--<echo>${version.file}</echo>
    <echo>${manifest.file}</echo>-->
    <echo>Auto Increment Build: ${version.name} =&gt; ${new.version.name}</echo>

</target>

使用

ant [-Dmanifest.file=<file>] [-Dversion.file=<file>] [-Dbuild.slot=<number>]
    -Dmanifest.file - path and filename AndroidManifest.xml. Default: AndroidManifest.xml in a folder with build.xml
    -Dversion.file - path and file name in which to store the number Build version. Default: version.properties folder with build.xml
    -Dbuild.slot - position of build number in version array. Default: 2, ie X.X.build.

Eclipse中的自动增量构建

Project | Properties | Builders | New | Ant Build
    Main
        Build file
            <path>/build.xml
        Arguments
            -Dmanifest.file=${workspace_loc://AndroidManifest.xml} -Dversion.file=${workspace_loc://version.properties}
    Refresh
        [x] Refresh resources upon completion
        (*) Specify resources
            [Specify resources] 
                <Project>
                    [x] AndroidManifest.xml
    Build Options
        [x] Specify working set of relevant resources
            [Specify resources] 
                <Project>
                    [x] res
                    [x] src
                    [x] AndroidManifest.xml

答案 4 :(得分:0)

我的解决方案使用了其他答案中的一些代码,XMLTask和Groovy来自动增加内部版本号。我还包含一个规则,用于执行git commit和tag以将版本号链接到版本控制中的特定点 - 对于错误跟踪很有用。

 <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>


  <path id="groovy.classpath">
    <fileset dir="/Users/deepwinter1/.gvm/groovy/current/lib/">
      <include name="*.jar"/>
    </fileset>
  </path>

  <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
    <classpath refid="groovy.classpath"/>
  </taskdef>

  <target name="update.build.number">
    <xmltask source="AndroidManifest.xml">
      <copy path="manifest/@android:versionCode" property="buildNum"/>
    </xmltask>
    <groovy>
      buildNum = Integer.valueOf(properties["buildNum"])
      properties["buildNum"] = buildNum + 1
    </groovy>
    <xmltask source="AndroidManifest.xml" dest="AndroidManifest.xml">
      <replace path="manifest/@android:versionCode"
        withText="${buildNum}"/>
    </xmltask>
    <antcall target="commit.and.tag.build">
      <param name="buildNum" value="${buildNum}"/>
    </antcall>
  </target>

  <target name="commit.and.tag.build">
    <exec executable="git">
      <arg value="commit"/>
      <arg value="-a"/>
      <arg value="-m"/>
      <arg value="Build Number ${buildNum}"/>
    </exec>
    <exec executable="git">
      <arg value="tag"/>
      <arg value="b${buildNum}"/>
    </exec>
  </target>

答案 5 :(得分:0)

你可以在这里找到一个“位”更好的解决方案答案...... https://stackoverflow.com/a/8156809/304270

Tiny c#工具,它将在每次新建构建之前执行,并在清单文件中增加适当的值..