Archive for March, 2008

Flash CS3 and _exclude.xml

Wednesday, March 26th, 2008

While working on a modest Flash framework at HZDG, I ran into a problem that everybody who works on a modest Flash framework runs into: there's no easy way to prevent classes from being compiled into a SWF in Flash CS3. Back in the days of AS2, classes could be excluded from compilation by creating an xml file like the following:

<?xml version="1.0" encoding="utf-8"?>
<excludeAssets>
	<asset name="MyClass" />
</excludeAssets>

Assuming that you had an FLA named "filename.fla," and saved the above xml as "filename_exclude.xml" in the same directory, the class MyClass would be excluded from your compiled SWF. This allowed you to create an application that used multiple SWF files without bloating the filesize and increasing the user's download time by including every class in every SWF. For some reason, however, this functionality was dropped in Flash CS3. Luckily, with the help of a tricky JSFL file, we can get it back.

Download the example and source files as a zip file or get them from my AS3 JSFL subversion repository. Then keep reading — I'll tell you what's going on.

Example

The example contains two FLA files: "library.fla" and "example.fla." The "library.fla" file contains only the following code on its first frame:

import PointlessThing;
var p:PointlessThing;

In practice, this FLA would be much more complicated, but I've simplified it for demonstration purposes. The only thing that matters is that one or more classes is imported and will be compiled into a swf. (The class I import — PointlessThing — is just that: it serves no real purpose other than to bloat the size of the SWF that it's compiled into so that we can be sure our _exclude file is working.) When we publish "library.fla," the resulting SWF is about 18k.

Our other FLA, "example.fla," is also very simple. It loads "library.swf" and, when the process is complete, creates a new PointlessThing and tells you how large the SWF file is:

import PointlessThing;
import flash.display.Loader;
import flash.system.LoaderContext;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;

var ldr:Loader = new Loader();
var request:URLRequest = new URLRequest('library.swf');
ldr.contentLoaderInfo.addEventListener('complete', completeHandler);
ldr.load(request, new LoaderContext(false, ApplicationDomain.currentDomain));

function completeHandler(e):void
{
	var p:PointlessThing = new PointlessThing();
	textField.text = 'This SWF is ' + this.root.loaderInfo.bytesLoaded + ' bytes.';
}

Compiling this FLA results in a SWF that's approximately 21k. Most of that is because of our PointlessThing class (which of course is only a stand in for the many classes that these two FLAs might share in a real-world application). This added bloat, however, would be completely unnecessary if we could simply use the PointlessThing definition that's already been compiled into the "library.swf" file. In other words, we need to prevent PointlessThing from being compiled into "example.swf." We could use the bridge pattern, but then we'd have to create new interfaces and we still wouldn't be completely rid of those extra bytes.

Instead, we can use the "Publish (obey _exclude.xml).jsfl" file included in the download above. This allows us to actually prevent classes from being compiled into our SWF using a system that many Flash developers are already familiar with. The files you've downloaded already include the _exclude.xml file for our example:

<?xml version="1.0" encoding="utf-8"?>
<excludeAssets>
	<asset name="PointlessThing" />
</excludeAssets>

In order for your _exclude.xml file to work, it must be named filename_exclude.xml (where filename is the name of your FLA) and saved in the same directory as the FLA.

This time, instead of publishing "example.fla" normally, run the jsfl file (Commands » Run Command…). Then open up the resulting SWF file — it should be about 3k, or less than 20% of the original!

Applications

This trick isn't just applicable to people creating Flash frameworks: virtually any project that loads external SWFs can benefit from eliminating redundant bytecode. And it's easy to fashion "Flash DLLs" that contain shared class definitions for runtime loading.

Though I chose to follow the _exclude.xml paradigm pioneered by previous versions of Flash, it doesn't really matter how the JSFL file determines which classes to exclude. In fact, having an _exclude.xml file for each FLA is almost certainly not an ideal situation. Because this technique is familiar to more developers than any other method of excluding classes, I figured it would provide a good starting point and allow for quick adaptation by users familiar with the process in AS2. Advanced developers, however, will probably benefit from picking apart the JSFL file and adapting it to suit their build process. All of my code is released under the MIT License so you can do whatever you want with it, but if you do wind up using it in Your Next Big Project, I'd appreciate a h/t.

ScrollPane

Tuesday, March 25th, 2008

I know a lot of work has gone into the Flash CS3 components and skinning them is much easier than it was with earlier versions, but doesn't it seem like they're still just too finicky? Well, it does to me. My simple ScrollPane class does everything you'd expect, but (unlike the component) leave the layout up to you. The result is a ScrollPane that's much more flexible and easily adapted to your pushing-the-boundaries-of-what-a-scroll-pane-can-look-like design. Don't want an up arrow? Don't include it. No thumb? No problem. Best of all, com.exanimo.containers.ScrollPane and com.exanimo.controls.ScrollBarare modeled after fl.containers.ScrollPane and fl.controls.ScrollBar, so you don't have to waste time learning new APIs. Better than best of all, I've put together six examples that demonstrate all the different ways to use the ScrollPane, and how easy it is to extend it.

Download the source code and example files as a ZIP or get them from my subversion repository.

Features

  1. Simple to skin
  2. API based on fl.containers.ScrollPane
  3. Doesn't muck with your layout
  4. Optional Thumb scaling
  5. Support for disabled ScrollBars
  6. Easy-to-implement easing
  7. Mouse wheel support (Windows only, for now)
  8. Thumb and arrow buttons are optional
  9. Accessors for setting the size of a line and page
  10. Accessors for setting the scrolling repeat interval and delay
  11. Uses interfaces in case you want to create your own implementation from scratch