Flex Monkey Patching and Framework RSLs

The Flex Framework RSLs (Runtime Shared Libraries) are a great way to reduce download time for your Flex application. But they have an unfortunate side effect… They break the ability to monkey patch Flex framework classes. The reason for this is the way that the Flex compiler structures a SWF file. Every Flex application has two frames. You can think of a “frame” as a container for compiled ActionScript classes. The Flex compiler puts as few things into the first frame as possible. This is so that the loading progress bar can come up quickly (as soon as the first frame has loaded). If you put too much on the first frame then you wouldn’t see anything happening until the whole first frame is loaded. When you monkey patch a Flex Framework class it usually will go into the second frame. The problem with monkey patching and the framework RSLs is that the RSLs get loaded in the first frame. The Flash Player’s class loader won’t overwrite classes so when the preloader finishes loading and then starts loading frame two (where the monkey patched class is) it will not overwrite the class loaded from the RSL.

The solution is to get your monkey patched class onto frame one. The easiest way to do this is to create a custom preloader that contains a reference to the monkey patched class. Here’s a simple one in which my monkey patched class is mx.controls.Button:

package
{
	import mx.controls.Button;
	import mx.preloaders.DownloadProgressBar;
 
	public class MyPreloader extends DownloadProgressBar
	{
		public function MyPreloader()
		{
			super();
 
			if (0)
			{
				var b:Button = new Button();
			}
		}
 
	}
}

Make sure you then tell your application to use your custom preloader:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" preloader="MyPreloader">

Now since Button is referenced from the preloader the Flex compiler will put Button and all of its dependencies on frame one. The monkey patched Button class will then be loaded BEFORE the RSLs thus making monkey patching work again! But the big caveat here is that now you have a ton of stuff on frame one (Button and all its dependencies – which we are trying to leave out of our SWF in the first place). And now the user won’t see the preloader progress bar until all of frame one is loaded – which now takes significantly longer than before.

While this works, it’s not ideal. What we need is a way to shove a single class into frame one. I’ve tried every way I can think of to do this but to no avail. What I’d hoped would work was to put my monkey patched class but none of its dependencies into a SWC and then use the -compiler.include-libraries mxmlc compiler flag to shove the monkey patched class into my SWF. But I couldn’t get compc to put just my monkey patched class into the SWC. Here is what I tried:

${FLEX_SDK}/bin/compc -source-path=src -debug=false -o=build/monkey.swc \
-external-library-path=${FLEX_SDK}/frameworks/libs,${FLEX_SDK}/frameworks/libs/player/9/playerglobal.swc \
-include-classes mx.controls.Button

But it appears that since compc sees the mx.controls.Button class in the -external-library-path it decides it doesn’t need to put my monkey patched Button in the SWC despite me telling it to.

Maybe someone else has some tricky way of getting just the monkey patched class into a SWC or onto frame one of the SWF. Otherwise please go vote for bug #19735.

This entry was posted in Flex. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Christian H. Mosveen

    Wild guess: Could you do something with the Frame metadata? http://blogs.adobe.com/rgonzalez/2006/06/modular_applications_part_2.html

  • Astor Digital

    in your compiler arguments you can use -ic=com.adobe.utils.Library

    where Library is a class containing the reference to Button class.
    //Library.as
    package com.adobe.utils
    {
    import mx.controls.Button;

    public class Library
    {
    //create instance
    var button:Button;
    }
    }

  • Pingback: TempusFactor » Blog Archive » links for 2009-03-11()

  • http://www.tink.ws/blog Tink

    Great info, never cross my mind before, thanks.

  • http://www.jamesward.com James Ward

    Thanks Christian and Astor. I tried both ideas. Couldn’t get either to work. I need someone with a bigger brain to figure this out. :)

  • Darrell Loverin

    You can load your monkey patched class before the Flex RSL without bloating frame 1.

    1. Use compc to compile Button into a SWC.
    2. Make an RSL from the SWC.
    3. Load the monkey patched RSL before the Flex RSL.

    This doesn’t solve the “only add the Button class without its dependencies” problem but it will make frame 1 smaller.

  • http://www.jamesward.com James Ward

    Thanks Darrell. That’s a good point. And a great reason to get bug #19735 fixed. :)

    I assume that you would also have to move the RSL / Library up in the Library Path in order to get it to load before the Framework RSLs. Or does the Flex Preloader always load custom RSLs before the Framework RSLs?

    -James

  • http://cksachdev.blogspot.com Chetan Sachdev

    I looked at the bug and it is closed. But I am not able to generate swc file with a single component. I get the following error say in case of a Button:
    Error: could not find source for class mx.controls:Button.

    Are you able to generate swc ? Is it really fixed ?

  • http://www.jamesward.com James Ward

    Hi Chetan,

    I think it’s been fixed for Flex 4.

    -James

  • Pingback: Monkey patches and Runtime Shared Libraries (RSLs) | FLEXible playground()

  • http://www.hrundik.ru/blog Nikita Petrov

    I’ve come up with better solution of monkey patches and RSLs which solves the problem of unnecessary class importing. You can check it out in my blog

  • http://riapriority.com/blogs/slon-vsapogah.php Slon_vsapogah
  • http://blogs.adobe.com/dloverin Darrell Loverin

    Here are more details on my comment posted on 03/13/2009.

    http://blogs.adobe.com/dloverin/2010/01/how_to_monkey_patch_when_using_flex_rsls.html.

    The preloader loads RSLs in the order specified by the -runtime-shared-library-path options. There is no special treatment of custom RSLs. RSLs with digests and those without digests (specified via -runtime-shared-libraries) cannot be intermingled. RSLs without digests are always loaded after the RSLs with digests. The -runtime-shared-libraries option is maintained for backwards compatibility.

  • Tom Gruszowski

    Can we monkey patch using the Flex 4 compc but include a Flex 3 file?

  • http://www.jamesward.com James Ward

    @Tom

    Maybe. It depends on what you are including.



  • View James Ward's profile on LinkedIn