One of the biggest annoyances when trying to test a Flash application is when you don’t know what version your user is currently looking at, this might be due to caching issues and what not.
The obvious solution is making sure your user can see the version number of your application at run-time and include that with a bug report or similar. I’ll be covering two different techniques to accomplish this.
Using conditional compilation
Our initial and current approach is using svnversion and compiler.define via Ant to include the version number as a constant.
<target name="Build">
<exec executable="/usr/bin/svnversion" outputproperty="svn.revision">
<arg value="."/>
</exec>
<mxmlc file="SomeApp.as" output="bin/MyApp-release.swf" debug="false">
<source-path path-element="src"/>
<define name="CONFIG::version" value="${svn.version}" />
</mxmlc>
</target>
This approach works just fine but you’re somewhat tied to using Ant to build you projects.
Embedding your entries file
After using svnversion for a while I thought there has to be a way to embed the version number using any compilation method, which lead me to the [Embed] meta-tag of AS3. This allows you to embed any file when specifying a mimeType of application/octet-stream.
You could for example embed a PSD file and read something from it at run-time.
[Embed(source="SomeFile.psd", mimeType="application/octet-stream")]
var SomeFileByteArray:Class;
var bytes:ByteArray = (new SomeFileByteArray()) as ByteArray;
trace(bytes.readUTFBytes(50)); // Read the first 50 bytes
And after tinkering around in the secretive .svn directory I came up with the SVNUtil class.
package {
import flash.utils.ByteArray;
public class SVNUtil {
private static const VERSION_PATTERN:RegExp = /dir\xa(\d+)\xa/;
[Embed(source="../.svn/entries", mimeType="application/octet-stream")]
private static var _entriesByteArray:Class;
public static function get version():String {
var entries:String = readEntries(20);
var matches:Array = entries.match(VERSION_PATTERN);
if (matches) {
return matches[1];
}
return null;
}
private static function readEntries(length:uint):String {
return (new _entriesByteArray() as ByteArray).readUTFBytes(length);
}
}
}
To use it, simply refer to it somewhere in your application.
public class MyApplication extends Sprite {
public static const VERSION:String = SVNUtil.version;
public function MyApplication() {
trace("Application version:", VERSION);
// Or you can call it directly
trace("Application version", SVNUtil.version);
}
}
As a final note this is experimental hacking, but it’s done at compile time so you won’t have to deal with run-time errors, I’m planning on posting up a similar class for Git when time allows.