5

Getting an IDE to automatically increment build numbers is a long discussed issue - I'm always surprised that something that seems so basic (to me) is so much work.

The highest scored question and answer (by quite a bit) for this topic are here: https://stackoverflow.com/a/8156809/150016 My problem is that the solution depends on .net and I'd prefer to avoid a .net dependency for Eclipse solution. I also want to avoid any dependency on VCS.

So, I'm looking for a solution that is portable and 'Eclipse-ish'. I think the best candidates are an Ant solution (which I will post) or a Java app similar to the dotNet app in the linked answer above.

(I didn't add my answer to that question because it has an accepted answer and is already a very long post. If the moderators prefer I will delete this question and add my answer to the question above.)

I was hoping for something comparatively simple but I don't think any solution to this problem really is simple.

Community
  • 1
  • 1
Tom
  • 17,103
  • 8
  • 67
  • 75

6 Answers6

8

In the project's properties dialog, under Builders, you can configure a script to run prior to building your apk.

In the properties dialog, select Builders from the list on the left. Click New to add a new script. On the dialog that pops up, select Program. On the ensuing dialog, call your Builder Program what you like in the Name field. Put the path to the script in the Location field. Give it a working directory in the Working Directory field. Note that you can specify variables in these fields (e.g., we use ${build_project:/libs/update_version.sh} to reference a script in the project's lib directory).

You'll want this to run before any of the other builders, so move it to the top of the list using the Up button.

On the Build Options tab of the Dialog (it's right under the Name field towards the top), you can select options for when you want this program to run.

I'm assuming something like Linux, Unix, or MacOS here. In those systems you can use grep or its variants to get the current versionCode, increment it, and then awk or similar to modify the file accordingly. Or, you could write a Ruby, Python, Perl, etc. script to replace the versionCode in the AndroidManifest.xml file. I suppose there are equivalent tools on Windows, but I'm not very familiar with that environment.

Brian Cooley
  • 11,622
  • 4
  • 40
  • 39
  • If one doesn't already have Ant, then your solution would certainly be simpler then the one I posted. On the other hand, I was hoping for something portable and (as you point out) a shell script won't work on Windows without something like Cygwin. A Python solution would be portable, but I think the ideal non-Ant solution would use a Java app since the user is guaranteed to have Java installed and running. – Tom May 25 '12 at 19:45
7

Have you tried to 'Maven-ise' your android project build ?

If you use the "maven-android-plugin", you can keep track of your project build with pom.xml's "version" tag.

In pom.xml you can increment the build version by using "versions-maven-plugin"

To reflect the incremented build number to to your AndroidManifest.xml you can use the Synchronizing Version technique within your pom file.

This way you can auto-increment the android project build number by running the "versions-maven-plugin" every time the app builds. The solution is also portable in the same way the Ant solution is.

I hope this can also solve the problem you have mentioned (and what I have understand). Please correct me if something is missing.

rizzz86
  • 3,862
  • 8
  • 35
  • 52
  • 1
    +1 Mavenize Android project requires some basic Maven background and is a little bit tricky to setup at beginning, but once you are familiar with it, it provides much easy and powerful configuration than Ant IMO. – yorkw May 25 '12 at 22:07
  • Interesting suggestion - I don't know much about Maven. I used Ant instead partly because it seems to be more closely associated with (and therefor useful for) Android development. I actually thought that my Ant solution was pretty good as a portable solution for Android Eclipse developers, but it has 0 votes, so I'll mark your Maven solution as the accepted answer. – Tom May 27 '12 at 22:12
3

Here is a solution that uses Ant. I must admit that getting Ant setup was a bit of a hassle, but it seems to be a widely used and powerful adjunct to Eclipse, so I believe it will turn out to be valuable for me in other ways.

Ant is the preferred solution for building Android SDK apps without Eclipse (as described here), but is not part of the ADT so you probably won't have it if you have just been using Eclipse.

So, the first step is to download and install Ant from here.

Next add Ant to your path and make sure that your path also points to the JDK (rather then the JRE). On Windows I found that I also had to create JAVA_HOME and point it to the root of the JDK.

We only need Ant for the auto-increment step - the intention is not to replace Eclipse and use it for the whole build - but it is useful to do a few steps in that direction to ensure that Ant is working. So, go to the root of your project and type

> android update project --path .

This creates a build.xml for your project. Once I had done that I was able to do

> ant release

and Ant built my project. If you want to keep going in that direction I found this article useful.

Next, I edited my project's new build.xml and added the following task (it can go anywhere, just not in the middle of another task/target)

 <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>

The task used above auto-increments a build number in a file (which it will create) called 'build.number' in your project's root. The rest of the task above puts the current build number into a resource string so that your application can retrieve it with this code:

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

Some people will prefer a solution that writes the build number to the application code in the AndroidManifest.xml. Here is an answer that includes a task to do that, but it requires a 3rd party Ant task (xmltask), and I'm a bit hesitant to have a 3rd party task modifying my manifest (which is now pretty huge) on every build. If you do decide to use that task then the corresponding Android code to get the build number would be:

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

Finally, you need to get Eclipse to run this Ant task every time you do a build.

Go to your project's properties, find the Builders, and click the button to add a new Builder. There are tons of options here but you only need to specify a few.

  • Give the builder some name by setting the Name: field.
  • Select the Buildfile:. I used the 'browse workspace' option to select it, and then it filled the field with "${workspace_loc:/appname/build.xml}"
  • Select targets from a list on the targets tab. In my case I had to remove the 'help' task (the default task in the build.mxl generated above), and then add the 'build.number' task. I suggest you only set a target for Manual Build:.

I moved the new Builder to be the first build step.

One issue with this solution is that every time you get Eclipse to deploy (run) your application it is considered to be a new manual build, even if the project hasn't changed. So, if you deploy your application to several devices, each device will have a different build with its own build number. One thing that will ameliorate this problem a bit is that Google says that a future ADT will allow for mutiple deployments in one operation.

This (above) was tested with Ant 1.8.4, Eclipse Indigo SR2 (3.7.2), ADT 20 preview 2 and SDK Tools 20, on Win7 32bit.

Community
  • 1
  • 1
Tom
  • 17,103
  • 8
  • 67
  • 75
1

My solution is based on using Ant (without 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>

Using

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.

Auto Increment Build in 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
Sikambr
  • 21
  • 3
0

My solution used some of the code found in other answers, XMLTask, and Groovy to automatically increment the build number. I also included a rule to do a git commit and tag to link the build number to a specific point in the version control - useful for bug tracking.

 <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>
deepwinter
  • 4,568
  • 2
  • 31
  • 37
0

a "bit" better workaround answer you can find here... https://stackoverflow.com/a/8156809/304270

Tiny c# tool which will execute before everynew new build and increase appropriate value in manifest file..

Community
  • 1
  • 1
Ewoks
  • 12,285
  • 8
  • 58
  • 67