Accessibility
Adobe
Sign in My orders My Adobe

Community Publishing

Created:
2009-11-14
Last Updated:
2009-11-17
by
User Level:
Intermediate/Advanced
Products:
Flash Builder Flex

Need more tips and tutorials?


Frameworkless MXML

It is a widely accepted belief that MXML language is tightly coupled with Flex Framework and as such, cannot be used for anything that isn't Flex framework. This article will show you how this is not altogether correct, and, maybe help you leverage more lightweight web application targeting Flash platform in less time.

 

 

Part 1. Introduction

A tiny example first:

<fl:Sprite xmlns:fl="flash.display.*" xmlns:fx="http://ns.adobe.com/mxml/2009"/> 

Yes, this is a minimal MXML application you can compile using MXMLC compiler. All you will have to do is to save this as FileName.mxml file and specify it as -file-specs parameter when running the compiler.

This and all further examples assume that Windows is used. All examples are compiled against SDK 4.0.0.10485 aka Flash Builder Beta 2.

 

Compile the example using this BAT file.

SET sdk=<SDK>\bin\mxmlc.exe
SET specs=<PROJECT>\src\tests\FileName.mxml
SET outputfile=<PROJECT>\bin\test.swf
SET exec=%sdk% -file-specs=%specs% -output=%outputfile% -theme
CALL %exec%
pause

 

The result should look something like this:

<PROJECT>\run>CALL <SDK>\bin\mxmlc.exe -file
-specs=<PROJECT>\src\tests\FileName.mxml -output=<PROJECT>\bin\test.swf -theme
Loading configuration file <SDK>\frameworks\flex-config.xml
<PROJECT>\bin\test.swf (558 bytes)
<PROJECT>\run>pause
Press any key to continue . . .

Note: <PROJECT> refers to the location of your project directory, the one that would usually contain src and bin folders. <SDK> refers to the root folder of your SDK installation.

Note: xmlns:fx="http://ns.adobe.com/mxml/2009" is required in case you are compiling against Gumbo (SDK 4.X and greater). It is required for the compiler to know which one of the frameworks is used. If you are compiling against SDK 3.X this namespace declaration is not required.

Note: -theme parameter is used to inform the compiler it should not try to include CSS accociated with either Halo or Spark frameworks.

Now, let's look into compiled SWF:

frameworkless-mxml-0

Yes, this SWF contains absolutely nothing related to the Flex framework. It has FileName class and a graphic symbol linked to it. This is a mandatory requirement for SWF format to have at least one graphic symbol that links to the stage. This symbol is the root of the application. However, you may compile SWF that has no symbols at all, classes only, such SWF can be used only as an application module (RSL - runtime shared library), but cannot be played in Flash Player alone.

 

Part 2. Resources

If you are familiar with MXML you may already know the syntax for embedding resources. This will work in frameworkless MXML too, however, it will require you to have some small subset of the framework classes embedded into your SWF.

<fl:Sprite xmlns:fl="flash.display.*" xmlns:mx="http://ns.adobe.com/mxml/2009">
<mx:Script>
    <![CDATA[
        [Embed(source='image.jpg')]
        private static var _resource:Class;
    ]]>
</mx:Script>
</fl:Sprite>

And here is what you get inside the SWF:

frameworkless-mxml-1

Note: @Embed(source='') syntax or <mx:Metadata> will work too.

<fl:Sprite xmlns:fl="flash.display.*"
    xmlns:mx="http://ns.adobe.com/mxml/2009"
    enterFrame="enterFrameHandler(event);"
    >
    <mx:Script>
    <![CDATA[
    import flash.display.Bitmap;
    import flash.events.Event;
    import mx.core.ClassFactory;
    public var embeddedBitmap:Bitmap;

    private function enterFrameHandler(event:Event):void
    {
        if (!this.embeddedBitmap || !super.contains(this.embeddedBitmap))
        {
            this.embeddedBitmap =
                new (this.inlineBitmap as ClassFactory).generator() as Bitmap;
            super.addChild(this.embeddedBitmap);
        }
    }
    ]]>
    </mx:Script>
    <mx:Declarations>
        <mx:Component id="inlineBitmap">
            <fl:Bitmap>
                <mx:Metadata>
                [Embed(source='image.jpg')]
                </mx:Metadata>
            </fl:Bitmap>
        </mx:Component>
    </mx:Declarations>
</fl:Sprite>

The above example will import more of the framework content, but it is here for demonstration purposes only. Practically, the best way to handle your resources is to have a separate SWC with all assets precompiled and to import the classes from that SWC. This will save you from redundant variable declarations with the only purpose of having something to attach [Embed] to ;)

The above code will compile into this SWF:

frameworkless-mxml-2

Note: There isn't any special class generated for the resource we embedded. This is because the <mx:Metadata/> applied to the component definition will instruct the linker to attach the symbol mentioned in [Embed] source to the class containing this meta data. This may come handy in times when you need some extended functionality of the class embedding the resource. Essentially, this is the same as if you have [Embed] printed on top of your class declaration.

Note: This kind of embedding will not make you import mx.core:BitmapAsset and mx.core:FlexBitmap, however, it will generate a new class extending directly from flash.display:Bitmap.

Note: <mx:Declarations/> is required in SDK 4.X. It does not exist in earlier SDK versions. This tag is there to make it possible for you to declare a visual component, that is not included in layout right away. However, all other visual componetns found outside the <mx:Declaration/> tag will be automatically added to the display list.

Now, are you concerned about redundant variables that you put in your projects for the only purpose of having something to stick the [Embed] tag to? Do you like the names for the classes you get when you use something like this:

[Embed(source='../../libs/cursors/hand_closed.gif')]
private static var _handClosedCUR:Class;

And then you get something like this in return: org.wvxvws.managers.CursorManager__libs_cursor_hand_closed_gif_67432356

Now, let's see how we can make it prettier and even smaller!

1. Create an MXML file for our cursor:

<?xml version="1.0" encoding="utf-8"?>
<!-- HandClose.mxml -->
<fl:Bitmap xmlns:fl="flash.display.*" xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Metadata>
    [Embed(source='../../../img/hand_closed.gif')]
    </mx:Metadata>
</fl:Bitmap>

 2. Create a class that will be the main class of or resource project:

<?xml version="1.0" encoding="utf-8"?>
<!-- Assets.mxml -->
<fl:Sprite
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:img="com.example.assets.*"
    xmlns:fl="flash.display.*"
    >
    <img:HandCursor/>
</fl:Sprite>

Note: this class is a pure convenience feature, it will not be embedded into application using the resource.

3. Write a configuration file:

<?xml version="1.0" encoding="utf-8"?>
<flex-config>
  <compiler>
    <source-path append="true">
      <path-element>${PROJECT_ROOT}\resources</path-element>
    </source-path>
  </compiler>
  <compute-digest>false</compute-digest>
  <load-externs>assets-externs.xml</load-externs>
  <include-classes>
    <class>com.example.assets.Assets</class>
  </include-classes>
</flex-config>

Note: ${PROJECT_ROOT} refers to your project root folder.

Note: assets-externs.xml is not required, but, I don't see a reason to embed framework classes in our own SWC since the framework classes may change while your images may not.

4. This is the listing of the assets-externs.xml:

<report>
  <scripts>
    <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.binding:EvalBindingResponder)" mod="1253111704661" size="943" optimizedsize="437">
    <def id="mx.binding:EvalBindingResponder" />
    <pre id="mx.rpc:IResponder" />
    <pre id="Object" />
    <dep id="mx.binding:Binding" />
    <dep id="AS3" />
    <dep id="mx.core:mx_internal" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.binding:Binding)" mod="1253111704786" size="4521" optimizedsize="2776">
    <def id="mx.binding:Binding" />
    <pre id="Object" />
    <dep id="RangeError" />
    <dep id="AS3" />
    <dep id="trace" />
    <dep id="mx.collections.errors:ItemPendingError" />
    <dep id="mx.core:mx_internal" />
    <dep id="XML" />
    <dep id="mx.binding:EvalBindingResponder" />
    <dep id="XMLList" />
    <dep id="flash.utils:Dictionary" />
    <dep id="Error" />
    <dep id="mx.binding:BindingManager" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.collections.errors:ItemPendingError)" mod="1253111705848" size="1024" optimizedsize="496">
    <def id="mx.collections.errors:ItemPendingError" />
    <pre id="Error" />
    <dep id="AS3" />
    <dep id="mx.rpc:IResponder" />
    <dep id="mx.core:mx_internal" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.binding:BindingManager)" mod="1253111704661" size="2094" optimizedsize="1136">
    <def id="mx.binding:BindingManager" />
    <pre id="Object" />
    <dep id="mx.binding:IBindingClient" />
    <dep id="mx.binding:Binding" />
    <dep id="AS3" />
    <dep id="Math" />
    <dep id="mx.core:mx_internal" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.rpc:IResponder)" mod="1253111671817" size="526" optimizedsize="175">
    <def id="mx.rpc:IResponder" />
    <pre id="Object" />
    <dep id="AS3" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\flex.swc(mx.core:mx_internal)" mod="1253111679176" size="190" optimizedsize="109">
    <def id="mx.core:mx_internal" />
    <dep id="AS3" />
  </script>
  <script name="C:\Flex_sdk_Gumbo_beta_2\frameworks\libs\framework.swc(mx.binding:IBindingClient)" mod="1253111704567" size="362" optimizedsize="105">
    <def id="mx.binding:IBindingClient" />
    <pre id="Object" />
    <dep id="AS3" />
  </script>
</scripts>
<external-defs>
  <ext id="Math" />
  <ext id="flash.display:Bitmap" />
  <ext id="XMLList" />
  <ext id="AS3" />
  <ext id="XML" />
  <ext id="flash.utils:Dictionary" />
  <ext id="RangeError" />
  <ext id="trace" />
  <ext id="Error" />
  <ext id="Object" />
  <ext id="flash.display:Sprite" />
  </external-defs>
</report>

 

Note: in order to get this file (it will be always specific to your machine because it contains information on location of framework libraries) you will have to do the following:

  • Compile the resource project first time with -link-report assets-externs.xml. This will generate the assets-externs.xml file containing all the classes contained in your project.
  • Edit it so it contains framework classes only, all classes mentioned in this file will not be included in the resources.swc.

5. Make a bat file for compiling an SWC containing Assets.mxml:

SET compc=<SDK>\bin\compc.exe
SET buildfile=<PROJECT>\run\build-resources.xml
SET outputfile=<PROJECT>\libs\assets.swc
SET exec=%compc% -load-config+=%buildfile% -debug=true -output=%outputfile%
CALL %exec%
@echo ------ resources SWC compiled ------
pause

6. Compile the project by running the BAT file. The resulting SWC now contains the com.example.assets.Assets class and com.example.assets.HandClose classes.

Note: com.example.assets.HandClose class is extending flash.display.Bitmap and not mx.core.BitmapAsset! Even though BitmapAsset class is very small, I don't like having unneeded classes in my project :)

Now, you can drop the compiled SWC into your project libraries folder and enjoy both pretty and meaningful assets names and remove [Embed]s from your classes!

frameworkless-mxml-3

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License