AIR Badge Installer Gotchas

If you want to pass parameters down to your application through the badge installer launch parameters:

  1. Make sure you set allowBrowserInvocation to true in your application descriptor file (appname-app.xml). Doh!

  2. Encode your launch arguments. A lot of characters are not permited.

My launch arguments were key value pairs which I organized as key1=“value1”,key2=“value2” in the launch argument string. This necessitates encoding keys and values which contain non alphanumeric characters, followed by an encoding of the entire launch argument string to flatten out unwanted charcters. In my first step I URL encoded the values (my keys contained only a-zA-Z0-9). In my second step I ran a custom URL encoder that used :FF syntax instead of %FF syntax, because colons come through fine in the launch argument string while percent symbols do not.

Here is the code for decoding the arguments. If you are looking for the class URLEncoding, you will find it in the oauth-as3 library. The URLEncoding.decode method is the same as the one below, except it uses percent instead of colons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
        /**
         * Decode the parameters passed as flashvars when invoking via a badge installer.
         * Decoding is a three step process:
         *     1. Decode ':FF' hex patterns from the string
         *     2. Split 'key1="value1",key2="value2"'
         *     3. Decode '%FF' url encoded patterns in values
         */
        public static function decodeFlashvars(encodedString:String) : Object
        {
            var result:Object = new Object();
            var decodedString:String = decode(encodedString);
            var paramPairs:Array = decodedString.split( /,/ );
            var regExp:RegExp = new RegExp( /^([^=]+)\=\"([^\"]+)\"/ );
            for( var idx:int=0; idx<paramPairs.length; ++idx ) {
                var kv:Array = (paramPairs[idx] as String).match( regExp );
                if( kv != null && kv.length >= 3 ) {
                    var key:String = kv[1];
                    var encodedValue:String = kv[2];
                    var decodedValue:String = URLEncoding.decode( encodedValue );
                    result[key] = decodedValue;
                }
            }
            return result;
        }
       
        /**
         * Decodes a string from the encoding used to get it through Badge Invoke.
         *
         * @param encodedString String to be decoded
         */
        public static function decode(encodedString:String):String {
            var output:String = encodedString;
            var myregexp:RegExp = /(:[^:]{2})/;
           
            var binVal:Number;
            var thisString:String;
           
            var match:Object;
           
            // convert all other characters
            while ((match = myregexp.exec(output)) != null && match.length > 1 && match[1] != '') {
                binVal = parseInt(match[1].substr(1),16);
                thisString = String.fromCharCode(binVal);
                output = output.replace(match[1], thisString);
            }
           
            return output;
        }

My launch argument encoding code is in Ruby. The URI::escape code is identical to my hex_encode method except for using percent instead of colons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def encode_args parameters
  params_str = parameters.sort.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(',')
  encoded_str = hex_encode(params_str)
end
 
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-]/

# Escape +value+ by URL encoding all non-reserved character.
def escape(value)
  URI::escape(value.to_s, RESERVED_CHARACTERS)
rescue ArgumentError
  URI::escape(value.to_s.force_encoding(Encoding::UTF_8), RESERVED_CHARACTERS)
end
 
def hex_encode(s)
  s.to_s.gsub(/([^ a-zA-Z0-9-]+)/n) {
       ':'+$1.unpack('H2'*$1.size).join(':').upcase
 }.tr(' ', '+')
 end

Comments