Tips for building AIR for Android Mobile Apps
Posted by Philip Bulley | Filed under Actionscript 3
There were a lot of learnings in building CrossTweet for Android. Here are a few tips I’d like to share with you.

Maintaining a Single Unified Codebase
With the help of conditional compilation, I’ve managed to keep a single unified codebase with separate ANT deployments. One example of where conditional compilation came in useful was when providing functionality to close the mobile app, something you wouldn’t do with the web app running in Flash Player.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Stop the compiler choking on NativeApplication when compiling for web using playerglobal.swc CONFIG::ANDROID import flash.desktop.NativeApplication; private function close( event:ErrorViewEvent ):void { CONFIG::ANDROID { // Only do this if compiling using AIR for Android using (airglobal.swc) NativeApplication.nativeApplication.exit(); } } // Don't forget to set the value of CONFIG::ANDROID when compiling, see the ANT build.xml |
Another example was when forcing the mobile app to automatically go fullscreen on startup, something which would produce errors if attempted within Flash Player.
1 | if(CONFIG::ANDROID) stage.displayState = StageDisplayState.FULL_SCREEN; |
Of course, keeping a entirely unified codebase can have it’s advantages, but may not be the best approach for every web & mobile app pairing. On a larger project, I’d probably lean towards unified models and controllers, but with separate views, something easily achieved with the dependency injection that a framework like Robotlegs provides.
Application Manifest
If you’re familiar with building desktop AIR applications, you will have created an AIR application manifest before. AIR for Android also requires a very similar manifest file, but with the addition of config which will be inserted into the native Android application manifest (native Android apps have their own manifest too and when using AIR for Android, they are effectively combined for convenience). It is here that you will need to request the specific permissions your app will require.
1 2 | <!-- CrossTweet only requires the internet access permission --> <uses-permission android:name="android.permission.INTERNET"/> |
Be wary of setting the “uses-configuration” elements, they are entirely necessary if you are targeting your app at a specific type of device running Android, but if you have one set accidentally (like I originally did) your app will simply not appear in the Market via an unsupported device. It goes without saying, that I would like to see an option on Android Market to show unsupported apps with accompanying warning messages as to exactly why they’re not supported on your device!
1 2 | <!-- I didn't realise this basically meant tracker ball, I originally thought a touchscreen could be classed as a five way nav! With this set, my app wouldn't appear in the Market on a Desire HD, where it would appear on a standard Desire - doh! --> <uses-configuration android:reqFiveWayNav="true" /> |
By way of example, here is the full “CrossTweet-app.xml” file with additions for Android.
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | <?xml version="1.0" encoding="utf-8" standalone="no"?> <application xmlns="http://ns.adobe.com/air/application/2.5" minimumPatchLevel="0"> <!-- AIR Application Descriptor File. See http://www.adobe.com/go/learn_air_1.0_application_descriptor_en. --> <id>com.bluebarracuda.CrossTweet</id> <name>CrossTweet</name> <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade. Values can also be 1-part or 2-part. It is not necessary to have a 3-part value. An updated version of application must have a versionNumber value higher than the previous version. Required for namespace >= 2.5 . --> <versionNumber>0.2.2</versionNumber> <!-- A string value (such as "v1", "2.5", or "Alpha 1") that represents the version of the application, as it should be shown to users. Optional. --> <versionLabel>v0.2.2 Beta</versionLabel> <filename>CrossTweet</filename> <description> <text xml:lang="en">What is CrossTweet? The large horizontal words running across the middle make up a tweet, recently sent out into the digital ether by Blue Barracuda or anyone else enjoying a life #LivingDigital. The vertical tweets are from people across the globe, simply tweeting about their everyday life. The moment the two intersect is where we live. That's the place where #LivingDigital becomes core to our outlook on life as a whole.</text> </description> <copyright>Copyright 2010, Blue Barracuda</copyright> <supportedProfiles>mobileDevice</supportedProfiles> <initialWindow> <content>CrossTweet.swf</content> <title>CrossTweet</title> <systemChrome>standard</systemChrome> <transparent>false</transparent> <visible>true</visible> <minimizable>true</minimizable> <maximizable>true</maximizable> <resizable>true</resizable> <width>800</width> <height>480</height> <x>150</x> <y>150</y> <minSize>800 480</minSize> <maxSize>800 480</maxSize> <autoOrients>true</autoOrients> <renderMode>cpu</renderMode> </initialWindow> <installFolder>Blue Barracuda/CrossTweet</installFolder> <programMenuFolder>Blue Barracuda/CrossTweet</programMenuFolder> <customUpdateUI>false</customUpdateUI> <allowBrowserInvocation>false</allowBrowserInvocation> <icon> <image36x36>icons/icon36.png</image36x36> <image48x48>icons/icon48.png</image48x48> <image72x72>icons/icon72.png</image72x72> </icon> <android> <manifestAdditions> <![CDATA[ <manifest android:installLocation="auto"> <!-- Added for Internet and debugging support --> <uses-permission android:name="android.permission.INTERNET"/> <supports-screens android:normalScreens="true"/> <uses-feature android:required="true" android:name="android.hardware.touchscreen.multitouch"/> <application android:enabled="true"> <activity android:excludeFromRecents="false"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> ]]> </manifestAdditions> </android> </application> |
ANT Buildfile
The central hub of the entire project has to be the ANT buildfile (build.xml), it neatly brings all deployments together and will be your best friend whilst testing/deploying/testing/etc.

This ANT buildfile will compile a SWF for the web as well as a SWF and APK for Android. It will create a self-signed certificate and if you have your device correctly connected to your computer, there are also tasks that will install, launch and even uninstall the app onto/from your device – c’mon, what more could you ask for?!! Don’t forget you’ll require the Flex SDK 4.1 and the latest Android 2.2 SDK at your disposal.
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | <?xml version="1.0" encoding="UTF-8"?> <!-- ************************************************************ ANT buildfile for unified codebase AIR for Android and Flash Player deployments. Author: Philip Bulley Last updated: 4th November 2010 ************************************************************ --> <project default="1) Compile SWF Web" name="CrossTweet"> <!-- Path to Flex and Android SDKs --> <property name="sdk_dir" value="C:\Program Files\flex_sdk_4.1.0.16076" /> <property name="android_sdk_dir" value="C:\Program Files\android-sdk-windows" /> <property name="mxmlc" value="${sdk_dir}/lib/mxmlc.jar" /> <property name="adl" value="${sdk_dir}/bin/adl.exe" /> <property name="adt" value="${sdk_dir}/lib/adt.jar" /> <property name="adb" value="${android_sdk_dir}/tools/adb.exe" /> <property name="sdk_lib_dir" value="${sdk_dir}\frameworks\libs" /> <!-- Project properties --> <property name="app_name" value="CrossTweet" /> <property name="app_id" value="com.yourcompany.CrossTweet" /> <!-- must match the id in the application descriptor --> <property name="app_root_dir" value="." /> <property name="assets_dir_name" value="asset" /> <!-- Certificate properties --> <property name="cert_name" value="CrossTweetCert" /> <property name="cert_pw" value="INSERT_PASSWORD_HERE" /> <property name="org_name" value="Blue Barracuda" /> <property name="org_unit" value="Creative" /> <property name="country" value="GB" /> <property name="key_type" value="2048-RSA" /> <property name="cert_validity" value="25" /> <property name="cert_path" location="${app_root_dir}/${assets_dir_name}/certificate" /> <property name="cert_file" value="${cert_path}/${cert_name}.p12" /> <!-- Project paths and filenames --> <property name="swf_filename" value="${app_name}.swf" /> <property name="android_filename" value="${app_name}.apk" /> <property name="app_descriptor_filename" value="${app_name}-app.xml" /> <property name="main_class" value="${app_root_dir}/src/Main.as" /> <property name="bin_dir" location="${app_root_dir}/bin" /> <property name="bin_debug_dir" location="${app_root_dir}/bin" /> <!-- note using single bin + bin-debug dir, change if you like --> <property name="bin_android_dir" location="${app_root_dir}/bin-android" /> <property name="bin_debug_android_dir" location="${app_root_dir}/bin-android" /> <!-- note using single bin + bin-debug dir, change if you like --> <property name="assets_dir" location="${app_root_dir}/${assets_dir_name}" /> <property name="lib_dir" location="${app_root_dir}/lib" /> <!-- Compile SWF to build-directory for packaging --> <target name="1) Compile SWF Web"> <java jar="${mxmlc}" fork="true" failonerror="true"> <arg value="-debug=false" /> <arg value="+flexlib=${sdk_dir}/frameworks" /> <arg value='-static-link-runtime-shared-libraries=true' /> <arg value='-target-player=10.0' /> <arg value="-file-specs=${main_class}" /> <arg value="-output=${bin_dir}/${swf_filename}" /> <arg value='-define+=CONFIG::ANDROID,false' /> <arg value="-library-path=${lib_dir}/as3corelib.swc" /> <arg value="-library-path=${lib_dir}/CasaLib_1.3.0.swc" /> <arg value="-library-path=${lib_dir}/greensock.swc" /> <arg value="-library-path=${lib_dir}/Library.swc" /> <arg value="-library-path=${lib_dir}/MouseManager.swc" /> <arg value="-library-path=${lib_dir}/robotlegs-framework-v1.1.2.swc" /> </java> </target> <target name="1a) Compile SWF Android"> <java jar="${mxmlc}" fork="true" failonerror="true"> <arg value="-debug=false" /> <arg value="+flexlib=${sdk_dir}/frameworks" /> <arg value="+configname=air" /> <arg value="-file-specs=${main_class}" /> <arg value="-output=${bin_android_dir}/${swf_filename}" /> <arg value='-define+=CONFIG::ANDROID,true' /> <arg value="-library-path=${lib_dir}/as3corelib.swc" /> <arg value="-library-path=${lib_dir}/CasaLib_1.3.0.swc" /> <arg value="-library-path=${lib_dir}/greensock.swc" /> <arg value="-library-path=${lib_dir}/Library.swc" /> <arg value="-library-path=${lib_dir}/MouseManager.swc" /> <arg value="-library-path=${lib_dir}/robotlegs-framework-v1.1.2.swc" /> </java> </target> <!-- Compile SWF to debug directory and copy assets to it --> <target name="2) Compile SWF Web (Debug)"> <java jar="${mxmlc}" fork="true" failonerror="true"> <arg value="-debug=true" /> <arg value="+flexlib=${sdk_dir}/frameworks" /> <arg value='-static-link-runtime-shared-libraries=true' /> <arg value='-target-player=10.0' /> <arg value="-file-specs=${main_class}" /> <arg value="-output=${bin_debug_dir}/${swf_filename}" /> <arg value='-define+=CONFIG::ANDROID,false' /> <arg value="-library-path=${lib_dir}/as3corelib.swc" /> <arg value="-library-path=${lib_dir}/CasaLib_1.3.0.swc" /> <arg value="-library-path=${lib_dir}/greensock.swc" /> <arg value="-library-path=${lib_dir}/Library.swc" /> <arg value="-library-path=${lib_dir}/MouseManager.swc" /> <arg value="-library-path+=${lib_dir}/robotlegs-framework-v1.1.2.swc" /> </java> </target> <target name="2a) Compile SWF Android (Debug)"> <java jar="${mxmlc}" fork="true" failonerror="true"> <arg value="-debug=true" /> <arg value="+flexlib=${sdk_dir}/frameworks" /> <arg value="+configname=air" /> <arg value="-file-specs=${main_class}" /> <arg value="-output=${bin_debug_android_dir}/${swf_filename}" /> <arg value='-define+=CONFIG::ANDROID,true' /> <arg value="-library-path=${lib_dir}/as3corelib.swc" /> <arg value="-library-path=${lib_dir}/CasaLib_1.3.0.swc" /> <arg value="-library-path=${lib_dir}/greensock.swc" /> <arg value="-library-path=${lib_dir}/Library.swc" /> <arg value="-library-path=${lib_dir}/MouseManager.swc" /> <arg value="-library-path+=${lib_dir}/robotlegs-framework-v1.1.2.swc" /> </java> </target> <!-- Show application without packaging --> <target name="3) Test Android App" depends="2a) Compile SWF Android (Debug)"> <exec executable="${adl}"> <arg value="${bin_debug_android_dir}/${app_descriptor_filename}" /> <arg value="${bin_debug_android_dir}" /> </exec> </target> <!-- Packaging the application to an air-file & save it in the publish directory --> <target name="4) Package Android App" depends="1a) Compile SWF Android"> <java jar="${adt}" fork="true" failonerror="true"> <arg value="-package" /> <arg value="-target" /> <arg value="apk" /> <arg value="-storetype" /> <arg value="pkcs12" /> <arg value="-keystore" /> <arg value="${cert_file}" /> <arg value="-storepass" /> <arg value="${cert_pw}" /> <arg value="${bin_android_dir}/${android_filename}" /> <arg value="${bin_android_dir}/${app_descriptor_filename}" /> <arg value="-C" /> <arg value="${bin_android_dir}" /> <arg value="${swf_filename}" /> <arg value="${bin_android_dir}/icons" /> </java> </target> <target name="4a) Install Android App on Device" depends="4) Package Android App"> <java jar="${adt}" fork="true" failonerror="true"> <arg value="-installApp" /> <arg value="-platform" /> <arg value="android" /> <arg value="-platformsdk" /> <arg value="${android_sdk_dir}" /> <arg value="-package" /> <arg value="${bin_android_dir}/${android_filename}" /> </java> </target> <target name="4b) Launch Android App on Device"> <java jar="${adt}" fork="true" failonerror="true"> <arg value="-launchApp" /> <arg value="-platform" /> <arg value="android" /> <arg value="-platformsdk" /> <arg value="${android_sdk_dir}" /> <arg value="-appid" /> <arg value="${app_id}" /> </java> </target> <target name="4c) Uninstall Android App from Device"> <java jar="${adt}" fork="true" failonerror="true"> <arg value="-uninstallApp" /> <arg value="-platform" /> <arg value="android" /> <arg value="-platformsdk" /> <arg value="${android_sdk_dir}" /> <arg value="-appid" /> <arg value="${app_id}" /> </java> </target> <!-- Creating a digital ID certificate --> <target name="5) Create New Certificate"> <java jar="${adt}" fork="true"> <arg value="-certificate" /> <arg value="-cn" /> <arg value="${cert_name}" /> <arg value="-ou" /> <arg value="${org_unit}" /> <arg value="-o" /> <arg value="${org_name}" /> <arg value="-validityPeriod" /> <arg value="${cert_validity}" /> <arg value="-c" /> <arg value="${country}" /> <arg value="${key_type}" /> <arg value="${cert_file}" /> <arg value="${cert_pw}" /> </java> </target> <target name="6) List devices attached"> <exec executable="${adb}"> <arg value="devices" /> </exec> <echo message="echo test ${org_name}" /> </target> </project> |
Another very useful reference is the Building ADOBE® AIR® Applications PDF guide. It will give you more insight on how you can configure your application, as well as recommended icon sizes, and much more.
Good luck, and if you make an AIR for Android app, I’d love to know about it.
2 Responses to “Tips for building AIR for Android Mobile Apps”
-
[...] insight and tips on how this was built, see my Tips for building AIR for Android Mobile Apps [...]
-
Very helpful, answered a lot of questions I had about ant build files. I ended up using your example to make my own build file for building an air app with custom java classes so that I could do task bar notifications etc… through the android os.
It’s in the market if you have any interest, air.com.justinbuser.BuzeyTunes