So you're building an Android app, and you want your app to display its build number on an About screen. You want the build number to be a unique identifier like the Subversion revision number. That's easy, you say: I'll build a simple About screen, put a TextView in it, and use Subversion keyword substitution, like this:
package com.kasperowski.example;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class BuildNumberExample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View aboutView = aboutWithKeywordSubstitution();
setContentView(aboutView);
}
View aboutWithKeywordSubstitution() {
TextView aboutView = new TextView(this);
aboutView.setText("Build number: $Rev$");
return aboutView;
}
}
And for bonus points, you could play some regex tricks or something to make the version number look like 42 instead of $Rev: 42$.
But, uh-oh! That's the revision number for that file, not the global revision number for your whole project. So it's no good as a build number.
You could play other games, like using a serial number file and writing a script that increments the serial number every time you build. But then you'll have a different problem: my sandbox and your sandbox will increment the serial number independently, oftentimes using colliding serial numbers. It would be a sandbox-specific serial number, hardly a good way to identify a build. You could build a shared database column with a globally incrementing serial number, but that's overkill.
Instead, use
svnversion
, a command line tool that returns the global version number of your repository. It is a stable, unique number that everyone can use, and it yields a true build identifier. At the command line, type svnversion, and you'll see your repository version number:
$ svnversion
22
To inject the svnversion number into your Android app's About screen, add a new resource to your
strings.xml
file:
Then, make sure you have an ant build script. I created my project using Eclipse, so I don't have a build script yet. Tell Android to create an ant build script for you:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, BuildNumberExample!</string> <string name="app_name">Build Number Example</string> <string name="app_svnversion">foo</string> </resources>
$ android update project --path .
Now you have a
build.xml
file, and you can type things like
ant clean
,
ant debug
, and
ant install
to build and install your app. Test your build script to make sure it works:
Add a new target to your$ ant clean Buildfile: C:\usr\local\workspace\build-number-example\build.xml [setup] Project Target: Android 1.6 [setup] API level: 4 clean: [delete] Deleting directory C:\usr\local\workspace\build-number-example\bin [delete] Deleting directory C:\usr\local\workspace\build-number-example\gen BUILD SUCCESSFUL Total time: 46 seconds $ ant install Buildfile: C:\usr\local\workspace\build-number-example\build.xml [setup] Project Target: Android 1.6 [setup] API level: 4 -compile-tested-if-test: -dirs: [echo] Creating output directories if needed... [mkdir] Created dir: C:\usr\local\workspace\build-number-example\gen [mkdir] Created dir: C:\usr\local\workspace\build-number-example\bin [mkdir] Created dir: C:\usr\local\workspace\build-number-example\bin\classes -resource-src: [echo] Generating R.java / Manifest.java from the resources... -aidl: [echo] Compiling aidl files into Java classes... compile: [javac] C:\android-sdk-windows\platforms\android-1.6\templates\android_rules.xml:248: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds [javac] Compiling 2 source files to C:\usr\local\workspace\build-number-example\bin\classes -dex: [echo] Converting compiled files and external libraries into C:\usr\local\workspace\build-number-example\bin\classes.dex... [echo] -package-resources: [echo] Packaging resources [aaptexec] Creating full resource package... -package-debug-sign: [apkbuilder] Creating BuildNumberExample-debug-unaligned.apk and signing it with a debug key... [apkbuilder] Using keystore: C:\Documents and Settings\kasper\.android\debug.keystore debug: [echo] Running zip align on final apk... [echo] Debug Package: C:\usr\local\workspace\build-number-example\bin\BuildNumberExample-debug.apk install: [echo] Installing C:\usr\local\workspace\build-number-example\bin\BuildNumberExample-debug.apk onto default emulator or device... [exec] pkg: /data/local/tmp/BuildNumberExample-debug.apk [exec] Success [exec] 17 KB/s (13601 bytes in 0.781s) BUILD SUCCESSFUL Total time: 2 minutes 2 seconds $
build.xml
file. This target executes svnversion and injects it into your
strings.xml
file.
At the command line, invoke the new ant target and then look at your<target name="foo-update-svnversion"> <exec outputproperty="build.svnversion" executable="svnversion"> <arg line="-n -c" /> </exec> <property name="match.start" value="<string name="app_svnversion">"/> <property name="match.end" value="</string>"/> <replaceregexp file="res/values/strings.xml" match="${match.start}.*${match.end}" replace="${match.start}${build.svnversion}${match.end}"> </replaceregexp> </target>
strings.xml
file. You'll see the svnversion number in
strings.xml
:
Now add some build targets to integrate your svnversion target with the default Android targets:$ ant foo-update-svnversion Buildfile: C:\usr\local\workspace\build-number-example\build.xml [setup] Project Target: Android 1.6 [setup] API level: 4 foo-update-svnversion: BUILD SUCCESSFUL Total time: 2 seconds $ cat res/values/strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, BuildNumberExample!</string> <string name="app_name">Build Number Example</string> <string name="app_svnversion">22</string> </resources> $
Finally, let's go back to your About screen. Add a method,<target name="foo-debug" depends="foo-update-svnversion"> <antcall target="debug"/> </target> <target name="foo-install" depends="foo-update-svnversion"> <antcall target="install"/> </target>
aboutWithSvnVersion()
, that grabs the svnversion resource and displays it on the screen:
Build your Android app by typingpublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View aboutView = aboutWithSvnversion(); setContentView(aboutView); } View aboutWithSvnversion() { TextView aboutView = new TextView(this); String svnversion = getResources().getString(R.string.app_svnversion); aboutView.setText("Build number: " + svnversion); return aboutView; }
ant foo-debug
or
ant foo-install
. This does exactly what you want, and now the world is safe again.
Resources:
摘自: