I believe that computers are the best things for doing repetitive tasks. I certainly am not, I either forget, or (mostly) don't do things in a consistent way - which isn't what I want.
One of the things I am likely to do is forget to up the version information in the manifest when I publish a new version of an Android app. In the past I've worked with configured build systems that have a auto version numbering feature and I got use to it (or maybe I got lazy).
I found this Stackoverflow post very useful in coming up with a solution, but it took me a while to fine tune it so it works just they way I want it. Earlier attempts would sometime cause continues building, which was a pain. So I thought I would publish my solution here in the hope that someone else will find it useful.
This solution was developed on Linux. I'm sure skilled Windows & Mac developers can adapt it to their platforms, but I am not such a developer. Linux is where my skill set lives.
Git has a nice feature in the git describe --dirty
command. It scans back down the commit log and finds the tag and then builds a version string from there. If this is a "production build" where the last commit has been tagged and all files have been checked in then that is your version string. If this is a development build then the last tag is appended with the number of additional commits and an abbreviated hash code. The --dirty
flag is just the cherry on the icing on the cake: it appends the word dirty
if there are any modified files not committed yet. This is perfect for your android:versionName
attribute in the manifest file.
For the android:versionCode
a number is required. This needs to clock for releases but not for development build, and as every release will have a tag with a version string I simply count these. I always tag my versions in the form v<major>.<minor>[.<patch>]
where <major>
, <minor>
and <patch>
are just numbers. So counting tags that start with a lower case 'v' followed with a digit are counted is all thats really needed here.
After trailing with a template manifest file I discovered that the best way was to simply use the AndroidManifest.xml file in the project base, edited using the stream editor sed
and deposit the result in bin/AndroidManifest.xml.
So I developed the script below, placed it in a scripts folder at the same level as my projects (so that they can all share the same script) and then configured a custom builder in Eclipse.
There is the script which I called 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
To configure the builder here are the steps:
1). Right click the project base and select "Properties" and then "Builders".
2). Hit the "New" button and select the "Program" option.
3). Name your version something like "<project> Auto Version". This string needs to be unique across all projects.
4). Configure the "Main" tab as follows:
4a). In the "Location" section use "Browse File System" and navigate and select the script file.
4b). In the "Working directory" section use "Browse Workspace" to select the project.
5). Leave the "Refresh resources upon completion" unchecked in the "Refresh" tab.
6). Don't set any variables up in the "Environment" tab.
7). In the "Build Options" tab:
7a). Make sure that "During manual builds" is ticked, and
7b). That "During auto builds" is also ticked.
7c). I now have everything else left unselected. I don't even allocate a console to it. The eagle eyed out there may have spotted that the script does output some information, but now I've got it working I just want the thing to run silently without bothering me.
8). Okay the build settings and then position your builder between "Android Pre-Compile" and "Java Builder".
Go back to developing your apps safe in the knowledge that they are being properly versioned, and check out your app's info. Isn't that version number cool. :-)
Steve
ok, here's a novel way of doing it:
for calculating version.code
:
git rev-list master --first-parent --count
this follows the versioning guideline. As it effectively finds the number of commits from the initial commit (inclusive) which is always incrementing from the previous version.
for calculating the version.name
:
git describe --tags --dirty --abbrev=7
build.xml
usually imports a custom ant script called custom_rules.xml
so making the content of the script as:
<?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>
would just do.
In a nut shell, it just replaces the android.versionCode
and android.versionName
with the current version code and name, stored in git.
-post-build
target, or (though I highly doubt you would require it) you could make it configurable and place it in some property (file or embedded; your choice)Enjoy.
HEAD
to calculate the build number; causes version downgrade issue when doing a build during development, and later when installing the stable version (or when doing a beta to main release transition). using the master
(or the branch which is used for production builds) ref instead.PS: relevant for AS users: Automatically versioning Android project from git describe with Android Studio/Gradle
Using 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")
...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With