Using Flash Symbols with ActionScript in Flex

Normally Flex will strip all ActionScript from an embedded Flash symbol. We’ve developed a technique called Shake’n’Bake SWFs (yes, I did watch Talladega Nights before coming up with the name), which allows you to utilize Flash symbols in Flex projects with all AS intact. I mentioned this technique at 360Flex, but didn’t go into much detail because there are better options available when using Flash CS3. A couple of people mentioned that they would like to learn about the technique, so I thought I’d blog about it.

Shake’n’Bake SWFs are relatively easy to implement. First, move all of the symbols you want to use into a new FLA in Flash 9 Public Alpha (or CS3), and publish a SWF – ensure the symbols have a Class name, and that they are set to export in the first frame. Next, embed the SWF in your Flex project as binary data.

[Embed(source="mySWF.swf", mimeType="application/octet-stream")]
var SWFBytes:Class;

Next, you need to instantiate the embedded SWF by using Loader.loadBytes. You could do this in an initialization handler, for instance.

var loader:Loader = new Loader();
loader.loadBytes(new SWFBytes());

This will reconstitute your SWF. Now you just need to reach into the SWF to pull out symbols or classes. Unfortunately, the reconstituted SWF is not immediately available. You will have to wait one frame or until the loader’s contentLoaderInfo dispatches it’s INIT event. Once it’s inited, you can use the loader’s contentLoaderInfo.applicationDomain.getDefinition method to pull out classes or symbols you’d like to use.

var SymbolClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition("com.gskinner.MyClass");
var symbolInstance:Sprite = new SymbolClass() as Sprite;

Pretty straightforward, but we’ve also built a class called FlashLib that handles most of the details for you, and a jsfl script that will set up and update the class for you with one click. Once you’ve downloaded / installed the MXP and restarted Flash, you will find two new commands in your Commands menu. “FlashLib – Create” will prompt you for your project location, then generate the SWF and a FlashLib.as file in the project directory. This command will also store the project directory, so that you don’t have to find it again on subsequent runs. If you ever want to change the saved project locations, you can use the “FlashLib – reset info” command to clear the saved location.

The FlashLib class that is generated will handle all of the Shake’n’Bake details for you. Simply add a listener for init, or call init() on FlashLib, and wait one frame (it takes one frame for assets to be available after the class is first accessed).

// because it uses static (class level) accessors, we need to add the listener to an eventDispatcher property:
FlashLib.eventDispatcher.addEventListener(Event.INIT,handleFlashLibInit);

You can verify that the symbols and classes are available by checking the init property at any time:

if (!FlashLib.inited) {
FlashLib.init();
}

Once it is inited, you can use the getDefinition and getInstance methods to get class definitions, and instances thereof from the Flash SWF. You can then use DisplayObjectWrapper to insert it into a Flex container.

function handleFlashLibInit(evt:Event):void {
// get a symbol instance from the SWF:
var myFlashSymbol:MovieClip = FlashLib.getInstance("MySymbol") as MovieClip;
// wrap it so that it will work in Flex layouts:
var myDOW:DisplayObjectWrapper = new DisplayObjectWrapper(myFlashSymbol);
// add it to the Flex container:
myFlexContainer.addChild(myDOW);
}

Considerations when using this technique:


  • You cannot (easily) strong-type your symbol instances, you will need to type them as a native object type (ex. DisplayObject, Sprite, MovieClip)
  • Symbols cannot be added to Flex layout controls without first being wrapped in IUIComponent friendly class (see my blog post on DisplayObjectWrapper for more details)
  • This technique will only work with AS3 content (from Flash 9 Public Alpha, Flash CS3, or Flex 2)

You can download the MXP here (includes the FlashLib classes and Flash commands). If you’re just interested in the FlashLib class, you can download it separately here. I’ll try to put up a simple demo in the next few little as well. To learn about and download the DisplayObjectWrapper class, view this entry.

Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

23 Comments

  1. This method has been around for a while hasn’t it? Ted used it in his Flex Preloading examples (http://www.onflex.org/ted/2006/07/flex-2-preloaders-swf-png-gif-examples.php).

    The class looks cool but I would have prefered it if you’d have built the frame wait inside it and then dispatched a Event.COMPLETE.

    I also prefer it if you’d kept the syntax the same as what is used in AS 3.0 i.e.

    if (!FlashLib.initialized) {

    FlashLib.initialize();

    }

    so i don’t end up with having to remember the differences between classes used (like AS 2.0 had).

  2. Hey Tink.

    I’m not sure how long this technique been around. I haven’t seen it before, but I wouldn’t be at all surprised if someone else has used it previously. Ted’s example does indeed embed a SWF as a binary data and use loadBytes to reconstitute it, but it doesn’t seem to provide for (or consider) symbol access specifically. I may be missing something though (I only had a brief glance at his code).

    As described in the article, I did internalize the wait, and the class dispatches an Event.INIT event via it’s eventDispatcher property. You may have been confused by my reference to the inited property – it is not necessary to check this if you subscribed to the INIT event, but it may be handy in some scenarios.

    I don’t believe that AS3 has any precedence for init versus initialize, other than the INIT event, but as Flex does use initialize (seems to be a minor player / framework disparity there), I will update the class to use initialize, and post it again shortly.

  3. Took a look at your FlashLib approach and like i understand it, FlashLib is a wrapper for the asset itself via the embed directive mapping to a ByteArray Object. So for each binary asset i need a customized FlashLib derivate ? That seemed a bit of too much dependency and less abstraction i would want it to have. I used a similar approach for sound imports with my AssetImporter class. The problem of timeline actionscripts being stripped by Flex i am new to. Anyhow i did a test with my modificated Sound AssetImporter and the ActionScripts seem to be keeped. So i wonder if the combination of binary embed and Loader.loadBytes() should be the only way. But i am new to Flex and maybe i am missing the point.

    Here my AssetImporter Class ( it is mixed with DisplayObjectWrapper to get it work in Flex )

    
    package de.pyramidon.asset
    
    {
    
    import flash.display.Sprite;
    
    import flash.display.DisplayObject;
    
    import flash.events.*;
    
    import flash.display.Loader;
    
    import flash.display.LoaderInfo;
    
    import flash.net.URLRequest;
    
    import flash.system.LoaderContext;
    
    import flash.media.Sound;
    
    import de.pyramidon.events.ImportAssetEvent;
    
    public class AssetImporter extends Sprite
    
    {
    
    private var importReady:Boolean;
    
    private var loader:Loader;
    
    private var swfPath:String;
    
    private var embedClass:Class;
    
    public function AssetImporter(swfPath:String, c:Class = null)
    
    {
    
    this.swfPath = swfPath;
    
    loader = new Loader();
    
    embedClass = c;
    
    }
    
    public function importAsset():void
    
    {
    
    if( importReady ) return;
    
    var url:String = swfPath;
    
    var req:URLRequest = new URLRequest(url);
    
    var context:LoaderContext = new LoaderContext();
    
    context.applicationDomain = flash.system.ApplicationDomain.currentDomain;
    
    if(embedClass) {
    
    loader.loadBytes( new embedClass() );
    
    }else{
    
    loader.load( req );
    
    }
    
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, importComplete);
    
    addChild(loader);
    
    }
    
    public function getInstance(embedClassName:String):DisplayObject
    
    {
    
    var clazz:Class;
    
    if(loader.contentLoaderInfo.applicationDomain.hasDefinition( embedClassName ) ) {
    
    clazz  =  loader.contentLoaderInfo.applicationDomain.getDefinition( embedClassName ) as Class;
    
    }
    
    return clazz ?  new clazz()  : null;
    
    }
    
    private function importComplete(ev:Event):void
    
    {
    
    importReady = true;
    
    dispatchEvent( new ImportAssetEvent( ImportAssetEvent.IMPORT_COMPLETE ) );
    
    }
    
    }
    
    }
    
    

    In mxml:

    [Bindable]

    private var assetRaw:DisplayObject;

    private var imp:AssetImporter;

    private function init():void

    {

    imp = new AssetImporter(“v01.swf”);

    imp.addEventListener( ImportAssetEvent.IMPORT_COMPLETE, assetImportHandler );

    imp.importAsset();

    }

    private function impTmp(e:Event):void

    {

    }

    private function assetImportHandler(e:ImportAssetEvent):void

    {

    assetRaw = imp.getInstance( “de.pyramidon.controls.GraphicButton” );

    assetRaw.addEventListener(“buttonClick”, assetClickHandler );

    }

  4. Henry,

    As implied by the name, and described in the article, the FlashLib class abstracts a Flash library SWF, and provides access to all of it’s assets, not a single asset (I know you understand this, but just to clarify). It is limited in this implementation to a single SWF, which I believe is likely sufficient for most developers, and provides the benefit of a single point of entry. That is, I can call FlashLib.getInstance from any point in my application without passing around a reference to a specific FlashLib instance. We also have a more complex implentation similar to your approach above that combines instantiable libraries with a static aggregator class to give you the best of both worlds, but I felt it was probably overly complex for the needs of most people.

    Cheers.

  5. This is great and a long awaited explanation of something that is core to working with flash and flex.

    You mentioned that Flash CS3 has some improved processes for dealing with this, can you tell us a bit more about this workflow? The announcement for CS3 products came out yesterday and i haven’t heard/seen anything of improved workflow between flash and flex. I’m wondering if I should implement the solution you have discovered or if there is a much improved or even more simplified workflow solution with the new Flash CS3.

    I’ve got a pretty big project that hinges on the requirement for producing flash assets to load into a flex app so thanks again for your time and willingness to share this information!

  6. By the way, i applied your same method for embedding flash font outlines to embedding/referencing flash library assets as we and it works fine. For example i can load a flash library item into a Flex image control just by simply using library.swf#myAsset. Is this not a good approach for dealing with library assets if there’s no need for actions in the library assets? If you were to use the embed method would that imply that the swf is loaded each time the emebeded swf is requested?

  7. Grant, for my example described above i converted your AS2 GraphicButton to AS3. The event behaviour works great when exported with the F9 pre alpha. When imported into Flex, the rollover/rollout events seem to be fired multiple times just by moving the mouse inside the hitarea of the button. Like i said, timeline actions get preserved. Using the approach of wrapping into UIComponent via your DisplayObjectWrapper should avoid any problems. Do you have an idea about the reason for this strange event behaviour, Grant ?

  8. What are the better ways in Flash CS3? I’ve been looking for something like this for a while now….hacking into components in flex is fun and all, but lately I’ve found myself thinking, “this actually might be easier in flash…” more than once. A way to merge the two together is extremely useful – I can build my complex animated componenets in flash and use Flex for the layout and to handle all of the business logic. Awesome!

  9. hi!

    great tool, but on the downside i dont have flash cs3. so is it possible and how to create a FlashLib-compatible.swf with flash8 or so?

    the thing is, i’m using flashdevelop + flex2 sdk for my as3-projects, so i have to [embed] things just like if i was using flex.

  10. >>I mentioned this technique at 360Flex, but didn’t go into much detail because there are better options available when using Flash CS3.

    Please could you explain this?

  11. I have been loading some swf libraries with “applicationDomain.getDefinition” in few different applications, from some reason I cann’t fully understand I’m unable to catch mouse events when I register them to the top containers, in order to make them work I have to register the event recursivly to all the child leaves. anyone has any ideas for solving this problem ???

  12. var button:SimpleButton = FlashLib.getInstance( “hiliteButton” ) as SimpleButton; button.addEventListener(MouseEvent.CLICK, playVideo);

    addChild(button);

    Man I love this. Thanks for sharing gSkinner team.

  13. Hi all, very nice job 🙂 very useful and clean , what about using frame actions ?

    I mean , i can read label and so on, how can i use a stop() in frame actions ? i can’t use frameactions in symbol exported, any hints ? 🙂

    thank u in advance, hierro.

  14. Hey grant.

    This is great stuff. It’s helped my workflow enormously so i can now work just like with MTASC injection, but it doesnt seem to keep exported library symbols (i.e. i can’t call addChild(new MyLibraryExportedSymbol)); )

    Is this correct?

  15. Thanks … Nices source codes

  16. hey grant, we’ve been using this for a while, but were disappointed to find ourselves making a separate AS class for each embedded swf.

    the other day, i realized that the solution is super-simple — just pass in the variable containing the embedded swf to the constructor of an instance of this class, and move the static functionality into instances.

    here’s the revision, for anyone who’s interested.

    http://www.transmote.com/share/code/EmbeddedLibrary.as

    cheers

  17. I have a library.swf with a movie clip Background_mc in the library I am trying to embed from this swf into another through a class.

    In this document class I do:

    [Embed(source=’library.swf’ symbol=’Backgroud_mc’)] Private var Background_mc:Class; Private var _myBG:MovieClip

    Function init():void{

    myBG = new Background_mc();

    addChild(myBG)

    }

    This throws an error:

    TypeError: Error #1007: Instantiation attempted on a non-constructor.

    What am I doing wrong?

  18. If you load the SWF containing the assets in the same way like loading an SWF class library, you can attain the same effect (see: http://www.novio.be/blog/?p=31)

  19. I just want to load a swf with a swfloader and get a list of symbols (movieclips) on the stage by name and library type. Isn’t there an easier way to do that than hack it in like this?

  20. I saw this happening my Air app, so just wanted to point out, if you are trying to use this technique in Air apps, you’ll get a Security Exception unless you add a LoaderContext to the Loader.loadBytes with the allowLoadBytesCodeExecution property set to true.

  21. Marcin Zajkowski July 21, 2009 at 11:58am

    Dear Grant Skinner,

    This is a great method, I really appreciate the easy-to-read breakdown and further preservation advantages of byte loading.

    Using this method I was able to effortlessly create a Flex Builder compatible FLVPlayback component, something I was trying to figure out for some time with out-of-the box CS3 script.

    Thank you very much!

  22. Hmm,

    Since im licenced to use Flash and Flex then i gave up a long time ago on the Embed tag. It was a horrible way to do things.

    Simply use a SWC file and put your code on say, the main timeline and import it to flex. You will maintain your code and symbol and itll be strongly typed.

  23. Super-Duper site! I am loving it!! Will come back again taking your feeds too now, Thanks

Comments are closed.