Tech Blog

Flex 3 to Flex 4 Migration Howto

Posted At : March 21, 2010 10:50 PM 0 Comments

I recently completed migrating an application from Flex3 to Flex4, and for my own reference, here's how I did it.

Note - this was done with flexsdk-4.0.0.13875, which was the most recent stable build at the time.

Phase 1: Get Flex3 code compiling with Flex4

Fix up stylesheets:

If you have a current Flex3 project and you are migrating to Flex4 you need to add the following lines at the top of your stylesheet.

This makes the default non-namespaced items in your stylesheet refer to the MX components. eg:

Button{fontSize:18;}
And to style up spark buttons you simply use:
s|Button{fontSize:18;}

To statically link or not?

Flex 4 defaults to dynamically linking runtime shared libraries. This produces smaller files, but if you are making desktop type applications or developing code while not connected to the internet you'll probably want to statically link the files. Add this to your compiler option:

-static-link-runtime-shared-libraries=true

You now should have a happily compiling app, however, to use all the new goodness of flex 4 there are still some more steps to be done.

Phase 2: Using all of flex 4

Update namespace to 2009

To update the namespace references for flex 4 I did the following search and replace:

Replace mx with fx namespace

<mx:Script> and </mx:Script>
becomes:
<fx:Script> and </fx:Script>

Similarly for other tags like this:

<mx:Binding> to <fx:Binding>
<mx:Metadata> to <fx:Metadata>

Add Declarations for non visual components

Wrap tag around non visual compoents. The compiler will complain about all these errors so just follow through and wrap them in

<fx:Declarations></fx:Declarations>
tags until all the errors go away.

Migrate States

Finally, at least for the project I migrated, I needed to convert all the state tags to the new format of inline attributes.

This shows up as the following error:

Error: State overrides may no longer be explicitly declared. The legacy states syntax has been deprecated.

So if you had something like this before:

<mx:State name="loading">
<mx:AddChild relativeTo="{myBox}">
<mx:Text textAlign="center" text="Loading..." selectable="false" />
</mx:AddChild>
... snip ...
<mx:VBox id="myBox">   
</mx:VBox>

It would now look something like this:

<mx:State name="loading">
... snip ...
<mx:VBox id="myBox">   
<mx:Text textAlign="center" text="Loading..." selectable="false"
   visible="false" includeInLayout="false"
   visible.loading="true" includeInLayout.loading="true"
/>

</mx:VBox>

Migrate StyleManager References

Stylemanager is not called as a global class any more and you need to use fully qualified references so:

thisImage.source = StyleManager.getStyleDeclaration("Image").getStyle("brokenImageSkin");
becomes:
thisImage.source = styleManager.getStyleDeclaration("mx.controls.Image").getStyle("brokenImageSkin");

When these have all been converted, your application should compile.

Then you can start leveraging the new functionality of flex4 and begin migrating your components to spark if necessary.

Migrating CSS from Flex 3 to Flex 4

Posted At : March 8, 2010 11:34 PM 0 Comments

Having searched around for how to make CSS work when migrating to Flex 4 from Flex 3 and finding lots of incorrect namespace declarations I thought I'd blog this as a reminder to myself:

If you have a current Flex3 project and you are migrating to Flex4 you need to add the following lines at the top of your stylesheet.

This makes the default non-namespaced items in your stylesheet refer to the MX components. eg:

Button{fontSize:18;}
And to style up spark buttons you simply use:
s|Button{fontSize:18;}

Note there were lots of ones that I found that were wrong.

Do NOT use:

This info was sourced from the Flex SDK Wiki.

Flex 4 RSL's and how to not use them

Posted At : March 8, 2010 10:55 AM

Flex 4 allows and defaults to using Runtime Shared Libraries (RSL's).

These have advantages of making flash movies using them work very well, but they can also require more http requests the first time they are used, and are not good for application development with Northcode.

To turn them off you need to add the following compiler flag:

-static-link-runtime-shared-libraries=true

Thanks to Flex Butterflies and bugs for the info.

ExtendoText project on google code

Posted At : April 7, 2009 11:09 PM 1 Comments

We've been busy squirrelling away on many projects and they are beginning to come to light:

One which is coming to light very early is a new text framework for actionscript which leverages flash 10 text engine.

It's very early alpha but is a good proof of concept and already solves some problems for us - namely the ability to simply create rich text area's that have superscript and subscript text.

It uses XML and CSS and completely seperates the formatting from the content.

Screenshot of extendotext 0.1

It can now:

  • Render a simple XML document
  • Apply styles including color, font and opacity
  • Plug in custom code for rendering images, video or any other XML tag you want to create.

The screenshot highlights a number of these features:

  • Bold, italic, super and subscript text
  • Text wrapping around custom display classes (Red and Green boxes)
  • Opacity applied to display objects (green box)

There is still a lot more to be done - including editing of text which is the next hard piece to knock over.

You can get it from the google code site

Keen to hear any feedback.

Cheers, Mark

More of AIR Gzip compression

Posted At : March 19, 2009 10:37 AM

Further to Marko's blog entry on implementing Gzip compression in AIR applications - turns out we were impressively hoodwinked.

By adding the 'Accept-Encoding':'gzip' header we were telling our apache server to serve up the compressed version of the content and we could see the content was compressed coming through Charles Proxy, and our application was working perfectly.

However, I started working on the exact same code the next day and straight away got an error - the application was erroring because it was getting binary data where it expected the decompressed XML data.

I turned Charles back on to see what was going on and it started working again. With my best sherlock holmes head on I rapidly deduced that Charles as well as proxying the request was also decompressing it helpfully for me.

Luckily I'd already come across the solution to the problem courtesy of Anirudh Sasikumar (GzipHTTPService) and Paul Robertson (Gzip Encoder).

I made some minor modifications to Anirudh's Gzip HTTP Service to do two things.

  • Always send the header 'Accept-Encoding':'gzip' if running a Desktop (Aka AIR) app.
  • Handle the case where the Gzip response that comes back is not gzip compressed. I.e. Charles already decrypted it or the server doesn't support gzip compression.
  • Change it to use version 0.2.0 of the gzip encoder

With these changes it is a drop in replacement for the <mx:HTTPService/> tag.

The changes are as follows:

...snip....
public function GzipHTTPService(rootURL:String=null, destination:String=null)
{
super(rootURL, destination);
         //If using AIR then set accept GZIP          if(Capabilities.playerType == "Desktop")
         {
            this.headers = {'Accept-Encoding':'gzip'};
         }
}

...snip....
else if ( body is ByteArray )
{
var barr:ByteArray = body as ByteArray;

try{
   var encoder:GZIPBytesEncoder = new GZIPBytesEncoder();
   /* decode the gzip encoded result */
   message.body = encoder.uncompressToByteArray(barr).toString();
}catch(error:IllegalOperationError){
   //Not gzip compressed - assume utf8    barr.position = 0;//reset to start of bytearray    message.body = barr.readUTFBytes(barr.length);
}
/* pass it on to HTTPService */
return super.processResult(message, token);            
}

...snip...

For convenience you can download the modified files from here.

Hope it helps.

Cheers, Mark

GZIP encoding in Adobe AIR/Flex - HOWTO

Posted At : March 6, 2009 1:27 AM

If you use HTTPService component in Flex or AIR to retrieve data from a server, you might want to consider gzipping the response. This can significantly reduce the packet size you get from the server, which results in a much better application performance.

This means that response packet is compressed by Apache web server and your client will need to decompress it. Fortunately, both Flex and AIR 1.5.1 natively support GZIP compression. However there are a couple of things you need to watch out for.

Firstly, you need to enable Apache Module mod_deflate in your virtual host.

In your AIR application, you need to tell HTTPService component to accept gzip encoding and AIR will take care of the rest:

<mx:HTTPService id="service" resultFormat="e4x" />
this.service.headers = {'Accept-Encoding':'gzip'};

If you are in a Flex project, specifying gzip encoding will throw the following error:

ArgumentError: Error #2096: The HTTP request header Accept-Encoding cannot be set via ActionScript.

This is because Flex apps run in a browser and the browser is responsible for determining encoding type and decompression (if required). Therefore, you cannot specify encoding type in Flex apps.

Our problem is that we use one core library for AIR and Flex applications. So the issue above can be avoided by conditionally specifying encoding type depending on the framework used. This can be done in 2 lines of code:

if(Capabilities.playerType == "Desktop")
this.service.headers = {'Accept-Encoding':'gzip'};

Note: this is not the complete solution - check out this entry for the rest of it :-)

Cheers Marko

AS3 BulkLoader example

Posted At : February 20, 2009 12:34 AM 1 Comments

I've been using AS3 BulkLoader for a while, which is great for loading multiple assets such as images and swfs into your application. Typical usage would look something like this:

instantiate BulkLoader object:

private var assetLoader:BulkLoader = new BulkLoader("instanceName");

add assets into the queue:

this.assetLoader.add("assets/myImage.jpg", {id:"key1"});
this.assetLoader.add("assets/myMovie.swf", {id:"key2"});
where id is the key, which is used to identify which asset to retrieve from the queue once it's been loaded.

To start loading assets you simply call the start() method:

this.assetLoader.start();

To get asset content, you would normally call getContent() method, which would return Bitmap for images or AVM1Movie for swf files. You could also call methods like getBitmap() and getAVM1Movie() to target specific file types.

The problem I encountered was that assets I was loading were encrypted. Therefore, I needed to read them in as ByteArray type and then decrypt them. Fortunately the latest version of BulkLoader has getBinary() method, but there is a trick to it. You need to tell BulkLoader to load assets in binary format when adding items into the queue:

this.assetLoader.add("assets/myImage.jpg", {id:"key1", type:BulkLoader.TYPE_BINARY});
this.assetLoader.add("assets/myMovie.swf", {id:"key2", type:BulkLoader.TYPE_BINARY});
And after all assets have been loaded, you get binary content:
var assetBinary1:ByteArray = this.assetLoader.getBinary("key1");
var assetBinary2:ByteArray = this.assetLoader.getBinary("key2");
Without specifying the type, BulkLoader will try to load data in text format which will result in the following error:
[BulkLoader] Failed to get content with url: 'file:///myFile.jpg'as type: [class ByteArray]

Setting the type to binary did the trick for me, so I thought I'd share it in case someone else falls into the same trap.

Oh, and I should thank Mark Lynch for helping me figure this out :-)

Marko

Can't Launch Air Apps after upgrading Flex Builder to 3.0.2

Posted At : January 13, 2009 8:33 PM

I recently upgraded flex builder to 3.0.2 to play with the new Flash 10 goodness and came across this little problem.

Whenever I clicked run it would just sit there for ages and never launch the app. If I clicked debug I got the following error:

Process terminated without establishing connection to debugger.

Command:

"C:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\bin\adl.exe" "C:\Documents and Settings\markl\My Documents\Flex Builder 3\SampleApp\bin-debug\SampleApp-app.xml" "C:\Documents and Settings\markl\My Documents\Flex Builder 3\DexterAir\bin-debug"

Output from command:

error while loading initial content

Turns out the solution is easy when you know how, thanks to this post.

The solution is a simple as changing the namespace in the app.xml file from:

to

Which is fine if you want to upgrade you app to 1.5 - not sure if there is still a way to compile apps for AIR 1.0 though.

Cheers, Mark Lynch

Flash Text Layout Framework - Getting Started

Posted At : December 16, 2008 6:16 AM 1 Comments

I finally got some time to play with Flash 10 and the new text functionality including the Text Layout Framework Beta

It gives very powerful control of the text layout but with this power come a few gotcha's which can trip you up.

The basic process for using the TextFlow for advanced text rendering is as follows:

  • Create a sprite container to hold the text
  • Import the text into a TextFlow object
  • Attach the container to the textflow object
  • Call updateAllContainers() on the textflow object
  • We also need to add event handlers for resize and graphics loading if we are using these features.

Create a sprite

_container = new Sprite();
this.textArea.rawChildren.addChild(_container);
this.textArea.addEventListener(ResizeEvent.RESIZE,resizeEvent);
Create a new sprite which get's attached to the canvas we've already created.
<mx:Canvas id="textArea" top="10" left="10" right="10" bottom="10"/>

Import the text into a TextFlow object

XML.ignoreWhitespace = false;         

var markup:XML = <TextFlow fontSize="30" fontFamily="Arial" whiteSpaceCollapse="preserve">
   <p fontSize="50" textAlign="center">Text Layout Framework Demo</p>
   <p>Text is now easy to control in Flash</p>
   <p><span>It can be formatted easily to do</span><span fontWeight="bold" whiteSpaceCollapse="preserve"> Bold</span><span>, </span><span fontStyle="italic">Italic</span><span>, </span><span textDecoration="underline">Underline</span><span> and </span><span lineThrough="true"> Strikethrough</span></p>
   <p>It can also finally do <span fontSize="20" alignmentBaseline="ideographicTop">Superscript</span> and <span fontSize="20" alignmentBaseline="ideographicBottom">Subscript</span></p>
   <p><a href='http://www.learnosity.com/techblog/'>Links</a> and inline images <img align="right" source="http://www.adobe.com/shockwave/download/images/flashplayer_100x100.jpg" /> are also available</p>
</TextFlow>;

_textFlow = TextFilter.importToFlow(markup,TextFilter.TEXT_LAYOUT_FORMAT);

This loads the XML and stores it in the _textFlow object.

Note: the XML.ignoreWhitespace is important otherwise it all the whitespace between tags will get stripped out and any formatted text will lose it's spacing.

Attach the container to the textflow object

_textFlow.flowComposer.addController(new DisplayObjectContainerController(_container,textArea.width,textArea.height));

Call updateAllContainers() on the textflow object

_textFlow.flowComposer.updateAllContainers();

That's it.

For bonus points you can add the event handlers to handle graphics loading and resize etc.

this.textArea.addEventListener(ResizeEvent.RESIZE,resizeEvent);
_textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGED,graphicStatusChangeEvent);
And the functions they call look like this:
public function graphicStatusChangeEvent(evt:Event):void
      {
         // the graphic has loaded (or failed to load) update the display          _textFlow.flowComposer.updateAllContainers();
      }   
      public function resizeEvent(evt:Event):void
      {
         //Resize event - recreate the flowcompser with the correct width and height          _textFlow.flowComposer.removeAllControllers();   
         _textFlow.flowComposer.addController(new DisplayObjectContainerController(_container,textArea.width,textArea.height));
         _textFlow.flowComposer.updateAllContainers();
      }

Make it selectable

To make the text selectable we just need to add an interaction manager. As easy as this:
//To make selectable
_textFlow.interactionManager = new SelectionManager();

I'm looking forward to implementing the rest of this in our projects that use flash text. It's so much simpler and cleaner.

Cheers, Mark

Extracting from sound from Flash (aka NellyMoser)

Posted At : July 23, 2008 1:58 PM 8 Comments

A current project that we are working on requires us to be able to record sound via a flash plugin. Initially I thought it would be nice and easy as I've seen demos of both video and audio broadcasting - however, the one big problem is that the current flash client only allows you to record video to a netstream, you can't get any access to it in the flash player.

So you need something like Flash Media Server or Red5 to record it.

However, once you record it to the server it is an flv and the audio codec is stored as a NellyMoser encoded audio portion. This codec is not supported by many applications and after a quick google found the nelly2pcm project on google code.

This will convert a flv sound file to a raw pcm file - which you can then do useful stuff with. So here's how to do it on a Ubuntu machine.

$ tar -xjvf nelly2pcm.tar.bz2
$ cd nelly2pcm
$ make
cc -Wall -c -o nelly2pcm.o nelly2pcm.c
cc -Wall -c -o nelly.o nelly.c
cc -Wall -c -o nelly_tables.o nelly_tables.c
cc -Wall nelly2pcm.o nelly.o nelly_tables.o -lm -o nelly2pcm
You should now have a nelly2pcm executable file in this directory.

You can run it as follows:

$ ./nelly2pcm test.flv > test.raw
mono Nellymoser stream with 16-bit samples at 44kHz

This will create a raw sound file with no headers and output the line above which you'll need for the next part.

To play this file back you can use sox (apt-get install sox)

$ play -r 44100 -c 1 -2 -s test.raw

If you've got all the options correct then this will play the file back. Once you got it correct you can then use sox to create a wav file which is essentially the same except that it has a header which contains all the settings (eg bitrate etc)

$ sox -r 44100 -c 1 -2 -s test.raw test.wav

From a wav you can convert to whatever you like. I'm looking forward to the Flash Player 10 release as this messing will no longer be necessary as it will support encoding with the free Speex codec.

Cheers, Mark

Update:

In the 12 hours since I wrote this post it appears that a DMCA takedown notice has been served on the nelly2pcm site and google have taken it down. I've no idea if it's related to this post or not and no details are available yet on the chillingeffects site but hopefully it will be updated shortly. As I mentioned earlier, I can't wait for flash 10 with the speex codec so we don't have to use Nellymoser, well done Adobe for including it.