Archive for January, 2010

Monkey Patching the Spark Button

This time around I’m going to monkey patch the Spark Button.
Like last time I’ll patch the label property setter. The label property setter
for the Spark Button is in spark.components.supportClasses.ButtonBase, not in
spark.components.Button as you might expect. I’m going to create an RSL
containing the ButtonBase class and its inheritance dependencies and then slide
that RSL into the RSL configuration.

Create an RSL

The ButtonBase class is compiled into spark.swc. I want to externalize
as many classes as possible in my custom RSL so I’ll externalize all the
libraries that spark.swc externalizes. That means I can externalize osmf.swc,
textLayout.swc, and framework.swc. My application is not using any classes from
osmf.swc so I won’t externalize that library and I won’t load that RSL either.

How do you know what libraries spark.swc is dependent on?
One way is to look at the build file for spark.swc and see what libraries are
on the external-library-path. Another way is to use the swcdepends tool. This
tool is helpful in looking at dependencies between swcs and finding out what
classes are causing those dependencies. I usually run it from the command line
like this:


The locale is set empty so that resource bundles are removed
from the output. The swcdepends tool behaves like mxmlc in that it
uses flex-config.xml and accepts the same configuration options. The output is
a list of all the swcs found in dependency order. The swc with the least
dependencies are at the top and the most dependencies are at the bottom. For
each swc in the list, there is an indented list to show the actually swcs it is
dependent on. Here an excerpt from the output showing the entry for spark.swc:






This shows that spark.swc is dependent on playerglobal.swc,
osmf.swc, textLayout.swc, and framework.swc. If you want to show what classes
are causing spark.swc to be dependent on the other libraries add the
-show-external-classes to the command line.

Creating the custom library for ButtonBase was pretty easy.
First I compiled with a list report and no externs file. The size of the RSL
was 10,801 bytes. This was already much smaller than the mx Button RSL and I
hadn’t even created an externs file yet. I copied the list report to the
externs file and added a “load-externs=externs.xml” to the compc ant task. Next
I edited the externs.xml file with the intent of removing ButtonBase and its
inheritance dependencies. I removed ButtonBase and the SkinnableComponent class
that ButtonBase extends. SkinnableComponent extends UIComponent but UIComponent
is in framework.swc and was already externalized. ButtonBase implements
IFocusManagerComponent which is also in framework.swc and does not need to be
excluded. So were done after removing just two classes.

Compile again and check the link report. The link report
shows just ButtonBase, SkinnableComponent and the root class so we are done.
The custom RSL’s final size is 6,198 bytes.

Add your RSL to the configuration

The custom RSL entry needs to be loaded after the framework
RSL and before the spark RSL. The framework RSL will provide UIComponent and
other classes we excluded. The custom RSL must be loaded before the spark RSL
so the monkey patched class will override the spark class.

Running the application shows that the monkey patched
version of ButtonBase is being used.

Download Source


How to Monkey Patch when using Flex RSLs

Monkey patchers run into problems when using Flex RSLs. In this post I’ll explain why monkey patching does not work when using RSLs and provide details of how to make it work. I’ll monkey patch the mx.controls.Button class in this post and ListCollectionView and Spark Button in later posts.

Why doesn’t monkey patching work when using RSLs? To answer this question it is important to understand two things:

  1. The Flash Player has a first-in-wins rule when loading classes.
  2. Flex applications contain two frames. The first frame contains few classes and loads the RSLs. The second frame contains the rest of the application’s classes.

Say you’ve monkey patched mx.controls.Button, which will end up in frame 2 of your application. In frame 1 of the application, the framework RSL will be loaded which contains the mx.controls.Button class. When frame 2 of the application loads the monkey patched version of mx.controls.Button is ignored because of the Flash Player first-in-wins rule.

When you monkey patch a class that is in frame 1, then you are done, you don’t need an RSL.

The basic steps I’ll use to monkey patch are:

  1. Create an RSL with just the monkey-patched file and its inheritance dependencies.
  2. Add your RSL to the configuration to get it loaded.

To demonstrate the process I created a project with a simple application that contains one button.

<mx:Button label=”My Button”/>

The project was developed using a pre-release version of Flex4, build


Create an RSL

My modification of Button is just a change to set label() so I can see if a Button in my application is a real or patched Button. When the Button’s label setter is called I just prepend “Monkey patched ” to the original value.


_label = “Monkey patched ” + value;

I started by adding to my source tree using the same package as Flex, “mx.controls”. Next compile your source into an RSL. From the command line it will look something like this:

>compc -directory -output=button -link-report=link.rpt -include-classes=mx.controls.Button -source-path=.

>optimizer button/library.swf –output -button.swf


>digest button.swf -swc-path=button

After running these commands the size of button.swf is 143,596 bytes. Looking at the link report, there are a lot of classes besides mx.controls.Button that we don’t need. Ideally, all we want in the RSL is mx.controls.Button. But the Flash Player requires classes that Button extends or implements to be defined when the Button class is loaded. Since we are loading this RSL before the framework RSL, we need to also include the classes Button extends and implements in framework.swc. For each additional class we include, we also need to include the classes it extends and implements.

Take the link report from the first compile of Button and copy it to a file we will use as our externs file. The externs file is what we will use to remove classes we don’t want in the RSL. I actually seeded my externs.xml file by copying and pasting the script children from framework.swc’s catalog. My thinking was that I wanted to exclude everything in framework.swc except Button and the classes it extends or implements. But now I can see that the externs file is much larger than it would have been if I had just started with the initial link report.

Next edit the externs file by removing the script elements for mx.controls.Button and all of its inheritance dependencies. After recompiling I was able to get the RSL size down to 35,152 bytes. That is still pretty big but it’s the best we can do because we need UIComponent and UICompoment is big. When monkey patching spark components we will be able to remove UIComponent and get a much smaller RSL.

Add your RSL to the configuration

Now that you have your RSL, you just need to add it to the RSL configuration. I created a local configuration file, main-config.xml, with the RSLs I wanted. You can start by copying the <runtime-shared-library-path> elements from flex-config.xml to your local configuration file. Then add the entry for your RSL before the framework RSL.

<!– monkey patch mx.controls.Button from Framework SWC –>






The order of the runtime-shared-library-path options is important because it determines the load order of the RSLs. The RSL URLs in my configuration file are all local SWF files so before running the application I will copy the RSLs from my SDK frameworks/RSLs directory to where my application lives.

When the new RSL is loaded for the first time you will mostly encounter verify errors because you missed removing an interface from the externs file. As you encounter a verify error, remove that class from the externs file and try again. Eventually the RSL will contain all the classes it needs and load without errors.

Finally, run the application to verify the monkey patched Button is being used.

The postings on this site are my own and don’t necessarily represent Adobe’s positions, views, strategies or opinions.