To illustrate the workflow of developing Android apps in Adobe Air I created a very simple application that can react to screen orientation changes, gestures and touches – it’s written in ActionScript.
The user interface consists of checkbox, label and a button.
If the user clicks the button or make a swipe gesture the background color will change to a random color.
Checkbox enables the screen orientation – this is an interesting feature since we can decide whether or not to let the screen rotate.
I used a set of Android-like components created by Kevin Hoyt, Adobe’s Platform Evengelist. They are very easy to use and mimic the Android look & feel pretty good.
Image may be NSFW.
Clik here to view.
The process is made of following steps
- create Flex Project
- generate the certificate
- package the Air application into an apk file
- install the apk to device / emulator
I assume that you have all the necessary dependencies already installed (Flex SDK with AIR 2.5 , Android SDK and an emulator /device), if not then check my previous post.
Creating Flex Builder project
1. Create a new Flex Project. Be sure to use Flex SDK merged with AIR 2.5 SDK.
Image may be NSFW.
Clik here to view.
In the second step change the main application file extention from ‘.mxml’ to “.as”, since we won’t be using Flex framework, only ActionScript 3.
Using Flex for mobile applications is possible but the performance would suffer. Until mobile version of Flex 4.5 isn’t released (should be available later this year) it’s better to stick to ActionScript only.
Image may be NSFW.
Clik here to view.
Modify application’s descriptor xml
Flash Builder has generated all the necessary files, there are only few thing to modify in the xml descriptor - set the <visible> tag to “true” and specify Android manifest – if your application is going to use Android APIs (camera, wifi, file access, etc.). If you don’t specify the functionality you need, the application won’t work properly.
The application main class looks like this:
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 | package { import com.greensock.TweenMax; import com.greensock.easing.Cubic; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.events.StageOrientationEvent; import flash.events.TransformGestureEvent; import flash.geom.Point; import flash.net.URLRequest; import flash.net.navigateToURL; /** * Adobe AIR Android application example * * @author Piotr Koscierzynski, flashsimulations.com * * */ [SWF(backgroundColor='0xf8f8f8',frameRate='31')] public class HelloAndroid extends Sprite { /* Android style components by Kevin Hoyt */ private var superButton:Button; private var autoOrientCheckbox:CheckBox; private var footerLabel:Label; // private var uiCreated:Boolean = false; private var labels:Array = ['Click me!', "Welcome to Android world!", 'Life is like a box of chocolates.', 'Have a nice day.']; private var counter:uint = 0; private static const TWEEN_TIME:Number = 0.6; private var tweenFunction:Function = com.greensock.easing.Cubic.easeInOut; private var backgroundSprite:Sprite; public function HelloAndroid() { addEventListener(Event.ADDED_TO_STAGE, onAdded, false, 0, true); } private final function onAdded(e:Event):void { removeEventListener(Event.ADDED_TO_STAGE, onAdded); init(); } /** * Stage resize handler. * */ private final function onResize(e:Event = null):void { //no stage instance available if (!stage) return; //ui not instantiated if (!uiCreated) return; var stageWidth:uint = stage.stageWidth; var stageHeight:uint = stage.stageHeight; //background backgroundSprite.width = stageWidth; backgroundSprite.height = stageHeight; backgroundSprite.x = 0; backgroundSprite.y = 0; //checkbox position var autoOrientCheckbox_x:int = autoOrientCheckbox.width - 30; var autoOrientCheckbox_y:int = 10; TweenMax.killTweensOf(autoOrientCheckbox); TweenMax.to(autoOrientCheckbox, TWEEN_TIME, {x:autoOrientCheckbox_x, y: autoOrientCheckbox_y, ease:tweenFunction}); //center the button superButton.setWidth(stageWidth - 20); var superButton_x:int = (stageWidth - superButton.width) >> 1; var superButton_y:int = (stageHeight - superButton.height) >> 1; TweenMax.killTweensOf(superButton); TweenMax.to(superButton, TWEEN_TIME, {x:superButton_x, y: superButton_y, ease:tweenFunction}); var footerLabel_x:int = (stageWidth - footerLabel.width) >> 1; var footerLabel_y:int = (stageHeight - footerLabel.height - 10); TweenMax.killTweensOf(footerLabel); TweenMax.to(footerLabel, TWEEN_TIME, {x:footerLabel_x, y: footerLabel_y, ease:tweenFunction}); } /** * If the <autoOrients>true</autoOrients> tag is set to true then the application will receive this event. * We can block the screen rotation by calling e.preventDefault(). * * */ private final function onOrientationChanging(e:StageOrientationEvent):void { //prevent the screen from rotating if (autoOrientCheckbox.selected == false) { e.preventDefault(); } } /** * Init stage align and listeners. * * */ private final function init():void { buildUI(); if (stage) { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener(Event.RESIZE, onResize, false, 0, true); stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, onOrientationChanging, false, 0, true); stage.addEventListener(TransformGestureEvent.GESTURE_SWIPE, onSwipe, false, 0, true); } //set UI elements positions onResize(); } /** * Handle screen swipe - change the background of the screen. * * */ private final function onSwipe(e:TransformGestureEvent):void { changeBgColor(); } /** * Build the user interface * */ private final function buildUI():void { //background backgroundSprite = new Sprite(); backgroundSprite.graphics.beginFill(0xFFFFFF, 1); backgroundSprite.graphics.drawRect(0,0, 1, 1); backgroundSprite.graphics.endFill(); backgroundSprite.mouseChildren = false; backgroundSprite.mouseEnabled = false; addChildAt(backgroundSprite, 0); //button superButton = new Button(labels[0], 300); superButton.addEventListener(MouseEvent.CLICK, handleButtonClick, false, 0, true); addChild(superButton); //checkbox - auto orientation enabled autoOrientCheckbox = new CheckBox('Auto orient screen'); autoOrientCheckbox.selected = false; addChild(autoOrientCheckbox); //label for footer footerLabel = new Label('flashsimulations.com'); footerLabel.addEventListener(MouseEvent.CLICK, handleFooterClick, false, 0, true); footerLabel.buttonMode = true; footerLabel.mouseChildren = false; addChild(footerLabel); uiCreated = true; } private function changeBgColor():void { TweenMax.to(backgroundSprite, 0.4, {tint:Math.random()*0xFFFFFF}); } private final function handleButtonClick(e:Event):void { superButton.label = labels[(++counter)%labels.length]; changeBgColor(); } private final function handleFooterClick(e:Event):void { navigateToURL(new URLRequest('http://flashsimulations.com')); } } } |
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 | <?xml version="1.0" encoding="utf-8" standalone="no"?> <application xmlns="http://ns.adobe.com/air/application/2.5"> <id>com.flashsimulations.air.HelloAndroid</id> <filename>HelloAndroid</filename> <name>Hello AndroAir</name> <versionNumber>1.0.0</versionNumber> <description>This application demonstrates the new Flash API for mobile devices (gestures, screen orientation). Created using Adobe AIR 2.5.</description> <copyright>Piotr Koscierzynski, flashsimulations.com</copyright> <supportedProfiles>mobileDevice</supportedProfiles> <!-- Settings for the application's initial window. Required. --> <initialWindow> <content>[This value will be overwritten by Flash Builder in the output app.xml]</content> <visible>true</visible> <autoOrients>true</autoOrients> </initialWindow> <android> <manifestAdditions> <![CDATA[ <manifest> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> </manifest> ]]> </manifestAdditions> </android> </application> |
2. Create an apk file and deploy it to the device / emulator.
Image may be NSFW.
Clik here to view.
Copy ‘HelloAndroid.swf’ and ‘HelloAndroid-app.xml’ into FLEX_SDK\bin directory, then run these commands
cd /Users/piotr/SDK/flex_sdk_4.1_air_2.5/bin ./adt -certificate -cn flashsimulations -ou piotrkoscierzynski -c PL -validityPeriod 25 2048-RSA android_cert.p12 SecretPassword ./adt -package -target apk-emulator -storetype pkcs12 -keystore android_cert.p12 -storepass SecretPassword HelloAndroid-emu.apk HelloAndroid-app.xml HelloAndroid.swf cp HelloAndroid-emu.apk /Users/piotr/SDK/Android_SDK/tools cd /Users/piotr/SDK/Android_SDK/tools ./adb devices ./adb -e install -r HelloAndroid-emu.apk
The application looks like this