Subversion Revision in Android App Version with Eclipse

As developers, we like to know exactly what code our customers are running when they report a bug. For years, across several companies and many projects, we’ve put the source control revision number into the reported version number. This works well and is a common practice. Here’s how we’re doing it for Android apps.

This method creates a three-component version number (e.g. 1.2.3) where the third component is the revision number of the code that was built as reported by subversion. Surely some of the code here will help for those using git, mercurial, perforce or other source control tools.

Let’s start with an ant task that gets the version number from Subversion and writes it into the AndroidManifest.xml file as part of the versionName property. As I want this to run on as many developers’ systems and our release system, I want to keep dependencies to a minimum, so I’m not using the SvnAnt task (although that would be shorter and more readable). This does require a supporting regular expression implementation library for ant, but it seems that my build system has that. The first half of this is neatly done with thanks to Matt Wizeman’s blog post.

<project default="svn-revision">
	<target name="svn-revision">
		<!--
		Exec `svn info` to get the revision of the code being built.
		Note that the output of this command is in "name: value" format
		so we can pretend it's a java properties file.
		-->
		<exec executable="svn" output="svn-info.properties">
			<arg line="info"/>
		</exec>
		<property prefix="svn" file="svn-info.properties"/>
		<echo>Revision: ${svn.Revision}</echo>

		<!--
		Write the revision number into the Manifest as the last
		segment of the VersionName property
		-->
		<replaceregexp file="AndroidManifest.xml"
			match='android:versionName="([^".]+\.[^".]+)(\.[^"]*)?"'
			replace='android:versionName="\1.${svn.Revision}"'
		/>		
		
		<!-- 
		Clean up
		-->
		<delete file="svn-info.properties"/>
	</target>
</project>

Save this file as svn-revision.build.xml in the root of your project folder. This assumes that the AndroidManifest.xml is in that same folder; if not, adjust line 18 appropriately. This also requires that there’s a versionName property with a value like “1.2” or “1.2.3” already there. If you have a different version naming scheme, adjust the regular expression in line 19 accordingly.

Next you need to add a new task to your Eclipse build process. This can be done through wizards or by adding/editing files. Below are the files; just remember to reload the project (or Eclipse) after you make the changes.

Create a launch configuration that will run your ant task.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.ATTR_REFRESH_RECURSIVE" value="false"/>
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${project}"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="${project_loc}/svn-revision.build.xml"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="ANDROID-APP"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/svn-revision.build.xml"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>

Save this to .externalToolBuilders/AddSvnRevisionToVersion.launch (this folder, relative to the root of your project space, is the default location that Eclipse stores this kind of stuff; if you are adding this to more than one project, then name it using a fully-qualified name, like com.example.AddSvnRevisionToVersion.launch, because Eclipse makes these names global). Note the “ANDROID-APP” in the XML — you’ll need to change that to the name of your project (from the <name> element in your .project file.).

And then modify the .project file with these changes. This file is located in the root of your project in your workspace.

Index: .project
===================================================================
--- .project	(revision 287)
+++ .project	(working copy)
@@ -6,6 +6,16 @@
 	</projects>
 	<buildSpec>
+ 		<buildCommand>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/AddSvnRevisionToVersion.launch</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
		<buildCommand>
 			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
 			<arguments>
 			</arguments>

This adds the launch task as the first task in your build process so that the AndroidManifest.xml is updated each time you build. Note that this also gets run when you run the Export Android Application wizard to build your release package. If your release process is automated, or doesn’t use Eclipse, you can just consume or run the ant project file, above, in your release build process.

Now you can display the versionName property in your ‘About’ activity so that your customers can report it if you ask them for it.

public class AboutView extends Activity {
	private final String TAG = AboutView.class.getName();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.about);
		TextView versionText = (TextView) findViewById(R.id.version);
		if (versionText != null) {
			versionText.setText(String.format(getString(R.string.version), getVersionName(), getVersionCode()));
		}

	}

	private String getVersionName() {
		String version = "??";
		try {
			PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
			version = pi.versionName;
		} catch (PackageManager.NameNotFoundException e) {
			Log.e(TAG, "Version name not found in package", e);
		}
		return version;
	}

	private int getVersionCode() {
		int version = -1;
		try {
			PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
			version = pi.versionCode;
		} catch (PackageManager.NameNotFoundException e) {
			Log.e(TAG, "Version number not found in package", e);
		}
		return version;
	}
}
Advertisement

7 thoughts on “Subversion Revision in Android App Version with Eclipse

  1. Hi! I had a problem with the ‘svn info’. I had the files in subdirectories with later modifications, rather than reported ‘svn info’. Because it indicates the last modification of some folder in the root of the project. For example:
    $ svn info
    Revision: 32
    $ svn info ./src/ru/bsrgin/myproject/MyActivity.java
    Revision: 45
    $ svn -r 32 -v log
    Changed paths:
    D /some-folder
    $ svn -r 45 -v log
    M /src/ru/bsrgin/myproject/MyActivity.java

    To solve this problem you can change Build Ant script at this:

    Revision: ${svnversion.Revision}

    And now my project version number has extra information about used working copy.
    android:versionName=”1.0.32:46M”

  2. Hello.
    After some problems on my French Linux distro, I have changed in svn-revision.build.xml two environmental variables : For native (non changing) language :

    BR,
    Olivier.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s