Archive for the ‘Flex’ Category

Embedding fonts in an ActionScript Project

Thursday, May 15th, 2008
Working with ActionScript projects can offer some rather interesting challenges with some of the most basic parts of Flash development. Things like preloading your application and using linked MovieClips from a library, not to mention using embedded fonts in your TextFields. This really becomes interesting when you want to use more than one font in a single TextField. And sure you can embed font files right into the AS class, but that doesn't always work. I've had numerous issues with otf fonts.

The method that I have had the best success with is using the same technique as embedding symbols from Flash AS2 swfs. Here's a step-by-step on how to do this.

1) Create a new FLA and set to publish to Flash 9 / AS2.

2) Create a New Font in the Library.

3) Set the Linkage to export for ActionScript on the first frame.

4) Publish the swf to a directory within your project.

5) Set non-embeded files to not copy to bin

6) Associate a standard Embed meta tag with a property of the class.
7) Create a new StyleSheet.
8) Create a style with fontFamily set to the name of the embedded symbol.
8) Assign the StyleSheet
package {
    import flash.display.Sprite;
    import flash.text.AntiAliasType;
    import flash.text.StyleSheet;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    
    [SWF(width="450", height="60", backgroundColor="#CCCCCC", frameRate="30")]
    public class EmbeddedFonts extends Sprite {
        private var _style:StyleSheet;
        private var _copy:TextField;
        
        [Embed(source="/embed/fonts.swf",symbol="Myriad Pro")]
        private var MyriadPro:Class;
        
        [Embed(source="/embed/fonts.swf",symbol="Myriad Pro Bold")]
        private var MyriadProBold:Class;
        
        public function EmbeddedFonts() {
            var main:Object = new Object();
            main.fontSize = 30;
            main.letterSpacing = 8;
            main.textAlign = "center";
            main.color = "#FFFFFF";
            main.fontFamily = "Myriad Pro";
            
            var main_bold:Object = new Object();
            main_bold.fontSize = 30;
            main_bold.letterSpacing = 8;
            main_bold.textAlign = "center";
            main_bold.color = "#000000";
            main_bold.fontFamily = "Myriad Pro Bold";
            
            _style = new StyleSheet();
            _style.setStyle(".main", main);
            _style.setStyle(".main_bold", main_bold);
            
            _copy = new TextField();
            addChild(_copy);
            _copy.autoSize = TextFieldAutoSize.LEFT;
            _copy.embedFonts = true;
            _copy.selectable = false;
            _copy.mouseWheelEnabled = false;
            _copy.styleSheet = _style;
            _copy.htmlText = "<span class='main'>I </span><span class='main_bold'>LIKE </span><span class='main'>MONKEYS!</span>";
            _copy.x = 450/2 - _copy.textWidth/2;
            _copy.y = 60/2 - _copy.height/2;
        }
    }
}
9) And voila.

Remoting for everyone

Monday, February 11th, 2008
Adobe opens up Flash Remoting (aka BlaszeDS) and the AMF protocol. How awesome is that? I've been a long time Remoting user and think it's the best way to go when you need data from a server. Although Adobe's offering is Java based, there are some really good PHP, .Net and other distributions. For more information on these check out The MidnightCoders, AMFPHP and OpenAMF.

FlashVars with Flex 2

Friday, January 4th, 2008
The switch from Flash to Flex can sometimes be frustrating when trying to do the things that we took for granite in Flash. FlashVars were so easy because they were automatically available on the root timeline object. Well, in Flex they are still automatically made available to you, just not in a place that you might expect.

The name/value pairs from FlashVars are added to the dynamic object Application.application.parameters and the named variables can be accessed as parameters.name = value.

FlashVars can be tricky though, especially when they are dynamically populated in the HTML by server-side code or when grabbing url parameters and adding them to FlashVars. You are not always guaranteed that the name/value pair will always be present, so you'll need to deal with the possibility of an undefined value. The following example shows a great way to deal with this situation which was given to me by a friend at work, be sure to check out her blog for other great Flash development tips. Also for additional information on this subject see the article in the LiveDocs.

The following example assumes that there are FlashVars defined in the HTML similar to this:
<param name=FlashVars value="uid=monkey">
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init();" viewSourceURL="srcview/index.html">
    <mx:Script>
        <![CDATA[
            public var userID:int;
            
            private function init():void {
                if ('uid' in Application.application.parameters) {
                    userID = int(Application.application.parameters.uid);
                } else {
                    trace("No user id was passed in!");
                }
            }
        ]]>
    </mx:Script>
</mx:Application>

Getting rid of the Flex 2 preloader

Thursday, December 20th, 2007
At some point in your Flex career you have probably wanted to get rid of the generic Flex 2 preloader that you always see when your application initially loads. If your application is fairly light weight there really is no need for it and why have an application that is easily recognizable as Flex. Luckily the answer is simple. All you have to do is set the usePreloader attribute to false.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" usePreloader="false">
</mx:Application>

Flex 2 and Flash 9 play nice
with DisplayObjectWrapper

Wednesday, October 17th, 2007
If you're a Flash developer making the switch to start using Flex, then this class from Grant Skinner is for you. DisplayObjectWrapper makes life much easier by enabling developers to easily get anything that inherits from DisplayObject (Sprite, Loader and Bitmap to name a few) to become a display child of a Flex container (Canvas, ViewStack, Accordion, etc). Awesome, now here are some code examples of how to work with SWFs in Flex 2.

This mxml file shows how to:
- load a Flash 9 SWF
- call a method within the document class of the SWF
- receive an event from the loaded SWF

One thing to keep in mind is the Flex security model. When you compile a Flex application it is by default set to be in the local-with-networking sandbox and the default for Flash 9 is local-with-filesystem which means the Flex application will not load the SWF when run locally. You will have to change the Local playback security setting in the Publish Setting window to Access Network Only.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" horizontalAlign="center" verticalAlign="middle" applicationComplete="init();">
    <mx:Script>
        <![CDATA[
            import com.gskinner.ui.DisplayObjectWrapper;
            import flash.display.Loader;
            import flash.events.*;
            import flash.net.URLRequest;
            import flash.system.ApplicationDomain;
            import flash.system.LoaderContext;
            
            private var loader:Loader;
            private var loadedSWF:DisplayObject;
            
            private function init():void {
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT;
                
                loader = new Loader();
                configureListeners(loader.contentLoaderInfo);
                
                var context:LoaderContext = new LoaderContext();
                context.applicationDomain = ApplicationDomain.currentDomain;
                var request:URLRequest = new URLRequest("fnine.swf");
                loader.load(request,context);
            }
            
            private function configureListeners(dispatcher:IEventDispatcher):void {
                dispatcher.addEventListener(Event.COMPLETE, completeHandler);
                dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
                dispatcher.addEventListener(Event.INIT, initHandler);
                dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
                dispatcher.addEventListener(Event.OPEN, openHandler);
                dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
                dispatcher.addEventListener(Event.UNLOAD, unLoadHandler);
            }
            
            private function completeHandler(event:Event):void {
                trace("completeHandler: " + event);
                //add the loaded swf to the display list
                loadedSWF = loader.content;
                displayArea.addChild(new DisplayObjectWrapper(loadedSWF));
                
                //listen for an event from the loaded SWF
                loadedSWF.addEventListener("fnineEvent", onFnineEvent);
                //call a method on a loaded SWF
                loadedSWF["testCall"]();
            }
            
            private function onFnineEvent(evt:Event):void {
                trace("onFnineEvent: " + evt);
            }
    
            private function httpStatusHandler(evt:HTTPStatusEvent):void {
                trace("httpStatusHandler: " + evt);
            }
    
            private function initHandler(evt:Event):void {
                trace("initHandler: " + evt);
            }
    
            private function ioErrorHandler(evt:IOErrorEvent):void {
                trace("ioErrorHandler: " + evt);
            }
    
            private function openHandler(evt:Event):void {
                trace("openHandler: " + evt);
            }
    
            private function progressHandler(evt:ProgressEvent):void {
                trace("progressHandler: bytesLoaded=" + evt.bytesLoaded + " bytesTotal=" + evt.bytesTotal);
            }
    
            private function unLoadHandler(evt:Event):void {
                trace("unLoadHandler: " + evt);
            }
        ]]>
    </mx:Script>
    <mx:Canvas id="displayArea" width="500" height="300" backgroundColor="0xFFFFFF" />
</mx:Application>

Also noteworthy is that the DisplayObjectWrapper is actually the parent of the loaded SWF. In very simplistic terms the display hierarchy is Flex Application > Container > DisplayObjectWrapper > SWF.

This class is the Document class for the SWF.
package {
    import flash.display.Sprite;
    import flash.events.Event;
    
    public class fnineApp extends Sprite {
        public function fnineApp() {
            trace("fnineApp.swf constructor");
        }
        
        public function testCall():void {
            trace("testCall() method called on fnineApp.swf");
            dispatchEvent(new Event("fnineEvent",true));
        }
    }
}
This basic idea will allow you to do all kinds of fun stuff. Enjoy.

Recording and streaming video with FM2 and AS3

Friday, October 12th, 2007
For some reason all of the code examples for using FM2 are in AS2. Converting the examples to AS3 can be a bit challenging, especially since there is one really key piece of information that is left out that is new to AS3 and specific to the use of FM2. The problem is the that FM2 only supports AMF0, but in AS3 the default setting for the NetConnection class' defaultObjectEncoding property is AMF3. Without changing this setting to AMF0, your code will seem to be correct, but will fail to connect without really telling you why. Check out the class that I created from the Adobe example and the MXML to use it.
package
{
    import flash.events.*;
    import flash.media.Microphone;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import mx.controls.VideoDisplay;

    public class StreamingFLV extends EventDispatcher {
        private var cam:Camera;
        private var mic:Microphone;
        private var rtmp:String;
        private var nc:NetConnection;
        private var ns:NetStream;
        private var local_video:VideoDisplay;
        private var _rtmp:String;
        private var _source:String;

        public function StreamingFLV(_lv:VideoDisplay,_r:String,_s:String) {
            _rtmp = _r;
            _source = _s;

            cam = Camera.getCamera();
            cam.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
            cam.addEventListener(StatusEvent.STATUS, handleCameraStatus);

            mic = Microphone.getMicrophone();
            mic.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
            mic.addEventListener(StatusEvent.STATUS, handleCameraStatus);

            local_video = _lv;

            NetConnection.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;
            nc = new NetConnection();
            nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            nc.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
            nc.connect(_rtmp);
        }

        public function startRecordFLV():void {
            local_video.attachCamera(cam);
            ns.attachAudio(mic);
            ns.attachCamera(cam);
            ns.publish(_source, "record");
        }

        public function stopRecordFLV():void {
            ns.close();
            local_video.close();
        }

        public function startPlayback():void {
            local_video.source = _rtmp +"/"+ _source + ".flv";
        }

        public function stopPlayback():void {
            local_video.close();
        }

        private function connectStream():void {
            ns = new NetStream(nc);
            ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
            ns.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            ns.client = this;

            dispatchEvent(new Event("onVideoReady"));
        }

        private function handleCameraStatus(event:StatusEvent):void {
            trace("handleCameraStatus: " + event);
        }

        private function activityHandler(event:ActivityEvent):void {
            trace("activityHandler: " + event);
        }

        private function netStatusHandler(event:NetStatusEvent):void {
            trace(event.info.code);
            switch (event.info.code) {
                case "NetConnection.Connect.Success":
                    connectStream();
                    trace("Connected");
                    break;
                case "NetStream.Play.StreamNotFound":
                    trace("No Connection!");
                    break;
            }
        }
        private function securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
        }
        private function ioErrorHandler(event:AsyncErrorEvent):void {
            trace("ioErrorHandler: " + event);
        }
        private function asyncErrorHandler(event:AsyncErrorEvent):void {
            trace("asyncErrorHandler: " + event);
        }
        private function onMetaData(info:Object):void {
            trace("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
        }
        private function onCuePoint(info:Object):void {
            trace("cuepoint: time=" + info.time + " name=" + info.name + " type=" + info.type);
        }
        private function onPlayStatus(info:Object):void {
            trace(info.toString());
        }

    }
}
And now the MXML:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    paddingTop="0"
    paddingLeft="0"
    paddingBottom="0"
    paddingRight="0"
    horizontalAlign="center"
    verticalAlign="middle"
    backgroundGradientAlphas="[0,0]"
    backgroundColor="#CCCCCC"
    applicationComplete="init();">
    <mx:Script>
        <![CDATA[
            import StreamingFLV;
            import flash.media.Camera;
            import flash.display.StageAlign;
            import flash.display.StageScaleMode;

            private var rFLV:StreamingFLV;
            private var pFLV:StreamingFLV;
            private var isPlaying:Boolean = false;
            private var isRecording:Boolean = false;

            private function init():void {
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT;
            }

            private function initRecordStream():void {
                rFLV = new StreamingFLV(video_record,"rtmp://los1aps-flash/zflv/test","recordSample");
                rFLV.addEventListener("onVideoReady",initUI);
            }

            private function initPlayStream():void {
                pFLV = new StreamingFLV(video_play,"rtmp://los1aps-flash/zflv/test","recordSample");
                pFLV.addEventListener("onVideoReady",initUI);
            }

            private function recordToggle():void {
                if (!isPlaying) {
                    record.label = "RECORDING";
                    rFLV.startRecordFLV();
                } else {
                    record.label = "RECORD";
                    rFLV.stopRecordFLV();
                }
                isPlaying = !isPlaying;
            }

            private function playToggle():void {
                if (!isPlaying) {
                    play.label = "PLAYING";
                    pFLV.startPlayback();
                } else {
                    play.label = "PLAY";
                    pFLV.stopPlayback();
                }
                isPlaying = !isPlaying;
            }

            private function initUI(evt:Event):void {
                record.enabled = true;
                play.enabled = true;
            }
        ]]>
    </mx:Script>
    <mx:VBox horizontalAlign="center">
        <mx:HBox>
            <mx:VBox horizontalAlign="right">
                <mx:VideoDisplay id="video_record" width="320" height="240" creationComplete="initRecordStream();" />
                <mx:Button id="record" label="record" enabled="false" click="recordToggle();" />
            </mx:VBox>
            <mx:VBox horizontalAlign="left">
                <mx:VideoDisplay id="video_play" width="320" height="240" creationComplete="initPlayStream();" />
                <mx:Button id="play" label="play" enabled="false" click="playToggle();" />
            </mx:VBox>
        </mx:HBox>
    </mx:VBox>
</mx:Application>
Enjoy!

Handy Flex 2 compiler arguments

Thursday, October 4th, 2007
Descriptions are from the Adobe Flex 2 Help that can be accessed in Eclipse under Help->Help Contents.

The topic that this information can be found under is:
Building and Deploying Flex 2 Applications > Building Flex Applications > Using the Flex Compilers > Using the application compiler

-benchmark=true|false
Prints detailed compile times to the standard output.

-default-frame-rate int
Sets the application's frame rate.

-keep-generated-actionscript=true|false
Determines whether to keep the generated ActionScript class files.

-optimize=true|false
This one should always be set to true.
Enables the ActionScript optimizer. This optimizer reduces file size and increases performance by optimizing the SWF file's bytecode.

Style your Flex 2 applications with ease

Tuesday, September 25th, 2007
The Flex Style Exporter is one of the best tools I've seen yet that support Flex development. Styles can be visually tricky, especially when your a developer styling your app on the fly. Colors don't always work out the way you expect them to. This tool really makes it easy and fun to get your styling just right. I don't know who wrote this, but I would like to shake their hand.

Flex 2 Style Exporter

Creating a custom logging target
The birth of LumberJack

Thursday, September 20th, 2007
I figured since I'm on the subject I would go ahead and share my code for creating your own custom logging target, called LumberJack. This particular target sends log message objects over a LocalConnection to a basic logging console that will output them into a text field. This tool can be a life saver and is one that I plan to continue to develop. Being able to see trace statements from a site running on any server, on any network can really help when debugging your application that is deployed somewhere besides your localhost. There are other tools out there that do this like RED|Bug, but this one is extremely simple and includes all the code so you can modify it to suit your needs.

First let's create the new log target class by extending the existing mx.logging.targets.LineFormattedTarget Flex class. Then override the logEvent method with the functionality desired and you're in business. Here's how I did it:

package {
    import flash.events.StatusEvent;
    import flash.events.AsyncErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.LocalConnection;
    import mx.logging.LogEvent;
    import mx.logging.targets.LineFormattedTarget;
    import mx.utils.ObjectUtil;

    public class LogMessageDispatcherTarget extends LineFormattedTarget {
        private var _conn:LocalConnection;
        
        public function LogMessageDispatcherTarget() {
            super();
            _conn = new LocalConnection();
            _conn.addEventListener(StatusEvent.STATUS, onStatus);
            _conn.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
            _conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
        }
        
        override public function logEvent(event:LogEvent):void {
            _conn.send("echo1","update",{level:event.level,category:event.currentTarget.category,message:event.message,time:this.includeTime});
        }
        
        //since these methods deal with LocalConnection errors we have to trace them.
        private function onStatus(evt:StatusEvent):void {
            trace("onStatus Event: "+ObjectUtil.toString(evt));
        }
        
        private function onAsyncError(evt:AsyncErrorEvent):void {
            trace("onAsyncError Event: "+ObjectUtil.toString(evt));
        }
        
        private function onSecurityError(evt:SecurityErrorEvent):void {
            trace("onSecurityError Event: "+ObjectUtil.toString(evt));
        }
    }
}


Building on the previous post, I have swapped out the TraceTarget for our new LogMessageDispatcherTarget.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init();">
    <mx:Script>
        <![CDATA[
            import mx.logging.Log;
            import mx.logging.ILogger;
            import mx.logging.LogEventLevel;
            import LogMessageDispatcherTarget;
            
            private var _log:ILogger;
            private var _loggerTarget:LogMessageDispatcherTarget;
            
            private function init():void {
                _loggerTarget = new LogMessageDispatcherTarget();
                _loggerTarget.filters=["*"];
                _loggerTarget.level = LogEventLevel.ALL;
                _loggerTarget.includeDate = false;
                _loggerTarget.includeTime = false;
                _loggerTarget.includeCategory = true;
                _loggerTarget.includeLevel = true;
                Log.addTarget(_loggerTarget);
                
                _log = Log.getLogger("ExampleRemoteLogger");
                _log.info("Logging rocks, Yo!");
            }
        ]]>
    </mx:Script>
</mx:Application>


The only thing missing now is the LumberJack console to receive and output the log messages. I won't go into it's implementation here, but you can download the Flex project. There will be more additions to LumberJack, such as message filtering, color coding and buffered output for improved performance. Check back for updates.

Removing trace() statements from
Flex applications

Wednesday, September 12th, 2007
Removing trace() from your code is a great way to optimize it and improve overall performance. This is easy enough to do in Flash by checking "Omit trace actions" in the Publish Settings window, but in Flex there is no such setting or compiler argument that I've seen. No worries, there is a solution.

Luckily Flex provides us with a logging framework in the mx.logging package. To implement logging within your application you have to specify targets that will get the log messages. One of the available targets is the TraceTarget. When you want to omit trace statements, just comment out the TraceTarget instantiation and that's it. See the example below on how to implement tracing with the Flex logger.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init();">
    <mx:Script>
        <![CDATA[
            import mx.logging.Log;
            import mx.logging.ILogger;
            import mx.logging.LogEventLevel;
            import mx.logging.targets.TraceTarget;
            
            private var _log:ILogger;
            private var _traceTarget:TraceTarget;
            
            private function init():void {
                _traceTarget = new TraceTarget();
                _traceTarget.filters=["*"];
                _traceTarget.level = LogEventLevel.ALL;
                _traceTarget.includeDate = false;
                _traceTarget.includeTime = false;
                _traceTarget.includeCategory = true;
                _traceTarget.includeLevel = true;
                Log.addTarget(_traceTarget);
                
                _log = Log.getLogger("ExampleLogger");
                _log.info("Your tracing like a pro!");
            }
        ]]>
    </mx:Script>
</mx:Application>

Working with Flex 2/AS3 will influence your AS2 development

Wednesday, June 13th, 2007
There are a lot of really great features within Flex 2 that Flash developers dream of having, but few know they already exist. When I moved to Flex 2 from Flash based AS2 development it was nice to see some native classes that had similar functionality to those that I had developed for my AS2 class library. In fact it gave me some really great ideas on how to improve some of my AS2 classes and even develop others from scratch. It's not too hard to emulate portions of the Flex 2 framework within AS2.

Once you start to use Flex 2 classes like the ArrayCollection, ObjectUtil and Logger it will be easy to see why you should take the time to make this functionality available to you in AS2. Be sure to peruse the Flex 2 Language Reference for some good ideas. You'll also probably want to start using Eclipse for your AS2 development, if so you should check out ASDT or FDT.

The reality for most Flash developers that are getting into Flex 2 or AS3, is that you will continue to have to do both AS2 and AS3 for some time to come. It would be great if the adoption rate of new Flash versions by clients would be as fast as the plug-in. But don't forget, there are still poor soles that are required to develop in Flash 6. Let's give them a moment of silence...

Sharing Links Is Good Karma

Tuesday, May 22nd, 2007
A few good links is all you need to learn something new off the interweb. Thought I would share a few of the ones I've come across so far in my path to Flex2/AS3 enlightenment. enjoy.

Adobe's ActionScript 3.0 Language and Components Reference
Adobe's Flex 2 Language Reference
Flex and ActionScript Error Codes Wiki
Good, Fast, Cheap
Oscar Trelles
jwopitz - flex/flash exploration

If you have some good links and want to improve your karma, please post a comment and share.

Remoting with Flex 2 and WebOrb

Thursday, May 17th, 2007
Remoting with Flex 2 and WebOrbRemoting is one of the coolest ways to get data from your server-side services or destinations as they are know in ActionScript. WebOrb was unbelievably easy to set-up and works great. In comparison to AMFPHP, it was considerably easier to set-up, required no modification to my PHP classes and has a very similar set-up to that of FDS. I found the documentation somewhat light, although the Quick Start guide was very helpful.

The only issue was an error in the WebOrb PHP code that is part of the install which generated this error message in the Eclipse console, "ReferenceError: Error #1056: Cannot create property isError on mx.messaging.AcknowledgeMessage." This seemed not to cause any problems when remoting except for the error message that kept showing up. Like any other anal developer I just couldn't have this, luckily the fix for this was fairly easy and I found it here. It was such a simple bug, I found it very surprising that Midnight Coders would release software with this error. Once I got past this everything has been perfect since.

So, what really made me choose WebOrb over AMFPHP? There are several reasons, but mainly the fact that it supports multiple languages and is upgradeable to include FDS comparable features for languages other than JAVA. Also they offer professional paid support, which can make a huge difference when deploying a large application for an important client and offer security features and a handy management console with the professional version. The final factor was that I found some good recommendations for its usage on sites that I respect and trust.

Testing Flash and Flex Applications

Friday, May 4th, 2007
I was on a call today with a client and their hosting vendor discussing the finer technical points of a new Flex 2/Flash 9 project that we are working on and the topic of load testing came up. The hosting vendor talked about load testing Flash as if it was something that was always done. I never really gave it much though before, normally I would just load test the server-side services and any other code that my Flash/Flex applications would connect to and figured that was all that could be done. Besides, does load testing even apply to code running in a browser? Where does the load come from if there is only one user? Where I work we would call this monkey clicking if anything. Monkey clicking is where the user clicks much faster than the developer would expect them to. Most sites built with Flash can be broken this way and is considered by my team the pinnacle of ActionScript development - to have a site that can survive monkey clicking.

So what are all the ways that a Flash/Flex application can be tested? First and foremost there is good old QA. There is no better substitute for a good QA a person, especially one that really understands how to properly test a Flash or Flex application. We were lucky enough to find someone who not only had previous experience QA'ing Flash, but was also an ex-game tester. Video games actually have a lot in common with Flash interfaces, something to consider when hiring a new QA person. The QA persons job is to test for monkey clicking, making sure links go to the right place, forms work properly with validation and tabbing, animations are doing what they are supposed to and so on.

Second is unit testing. Wikipedia describes the benefits of unit testing as: The goal of unit testing is to isolate each part of the program and show that the individual parts are correct. A unit test provides a strict, written contract that the piece of code must satisfy. As a result, it affords several benefits. This is a great way to go, especially if you use a class library in all of your projects. By using reusable code that has been throughly tested, you effectively reduce the amount of QA needed for any project that uses your library because you can have very reliable nut and bolts to build with. If you don't have your own application and/or architectural framework to build upon there are many to choose from, such as Cairngorm and As2lib.

Third is load or stress testing. There are many tools that can be used to test your PHP, .NET, JAVA or whatever your using, but what about ActionScript? A good load testing program will "record" a users actions and then play them back over and over to simulate multiple users at once. This might work for an HTML based site, maybe Silverlight will do better with this, but Flash is somewhat of a black box in this department. So far I have not found anything to simulate a user within a Flash application. Sure I could write a special testing application in ActionScript to make calls to the server in the same way that my application does, but is this cost effective? I think the problem lies in the fact that every Flash application is created with it's own custom logic, unlike HTML where everything is built with the same components. Links, buttons and forms will always work the same in HTML, but not true in Flash - maybe Flex. There is a load testing framework for Flex, but it mostly concentrates on load testing Flex Data Services and can be found on Adobe Labs. Even this uses a special application to simulate the calls to the server and not the actual application you created.

As in most interactive marketing based work, especially those that are built in Flash, things like QA, unit testing and load testing don't get done or gets very little time because of poor scoping, budget, project delays or little understanding for the importance of testing. It's a constant fight for us developers, sometimes I think we're the only ones who consider what we do is actually software development and not just brochureware. My previous boss (who was the GM of our office) actually ridiculed me in front of all the senior managers in our office because I tried to make this point, which ended up being the beginning of the end for me at that job. I realized that my methodologies on web development would never be taken seriously, hence I would not get the time and resources to do the job right, so I left and got a new job. Too bad for them, she was pissed when I left. I guess that makes my point as clear as possible.

Preparing for ActionScript 3

Thursday, May 3rd, 2007
We're about to start some pretty big projects for some great clients and best of all they are going to be Flex 2/Flash 9. It's nice to have clients that want to use the latest and greatest just because they are. They scary part is that we have a lot to learn in short period of time, so I thought I would share what we're doing to ramp up for the challenge. Mainly there's a lot of reading. Here's a few titles that are already available at your book store that are always worth the cover price.
  • ActionScript 3.0 Cookbook:
    Solutions for Flash Platform and Flex Application Developers
  • Foundation Actionscript 3.0 Animation: Making Things Move!
As usual not all the classics are out yet, mainly Colin Moock's book. But there is a ray of hope and a way to get it before it comes out. O'Reilly has this new feature called 'Rough Cuts' that allows you to get PDF versions of upcoming releases well before they come out. Go to www.oreilly.com, search for the following titles and buy the Rough Cuts. It costs $9.99 to start which gets you the PDF of the book in it's current iteration. When it comes out you get charged the remaining price of the book and it ships to you. The best part is that you can give feedback to the authors and potentially help shape the final outcome of the book. Here's the one's that I got:
  • ActionScript 3.0 Design Patterns
  • Essential ActionScript 3.0
  • Programming Flex 2.0
There are also a fair amount of sites that have great information, but here is one that I found particularly interesting that a co-worker sent to me. http://actionscriptcheatsheet.com/blog/quick-referencecheatsheet -for-actionscript-20/

This is also a good resource by Adobe:
http://livedocs.adobe.com/flex/2/langref/migration.html

As we get more into the development of our projects I'll post more about our experiences, sample code and eventually the sites themselves.