AS3, Custom Flex / Flash Preloaders, Apache 2, mod_deflate (formerly known as gzip) and a Sea Of Tears.
UPDATE: This *almost* did the trick. See the full update below. Writing a movie preloader in “pure” ActionScript 3 is reputedly more complex than creating preloaders have been previously. As I’ve just now had the opportunity to do some Flash development, I’ve been largely spared the half-script, half-Flash-timeline implementations that were common preceding AS3. Still, getting the ‘pure’ AS3 version to work has not been without stumbling blocks, which I document after the jump in hopes that someone else can avoid them. I’m doing all my Flash development in Flex Builder, using Actionscript projects. Why not Flash CS3? Well, I think anyone who’s used an IDE — or even a pretty decent text editor — would agree that the Flash CS3 Actionscript editor is not ideal for writing any significant amount of code. As soon as you start moving your work into classes, and thus, standalone actionscript files, moving between your main executable swf and the other files is an absolute chore. Not to mention that as a programmer, workflows that use the library and stage to import and position assets seem inefficient, prone to bugs, and not terribly accurate: it’s much faster for me to type three or four lines to embed a bitmap and instantiate a Sprite exactly where I want it, plus I can drop-in replacements to an assets folder and simply re-compile instead of having to do a ton of class-linking and other jiggery-pokery in the library. Using the Flex SDK for compiling also gives me access to the EMBED metatag which lets me avoid having to add assets into the library. The Embed metatag DOES NOT WORK IN CS3, so this was a big motivation to switch to FlexBuilder as soon as possible. FlexBuilder provides easy access to my project files, useful auto-completion (handy to someone new to the AS3 packages and syntax), and files well organized on tabs instead of multiple windows that bounce around and seem to get dragged out of place if you look at them cross-eyed. My only complaints about FlexBuilder is that out-of-the-box auto-indention is not offered (bad indents drive me crazy — I’ve given up on many an editor because I couldn’t easily reformat my files), and that I can’t use vim (well, yet — I’m plotting ways to make this happen). Once out of the Flash CS3 environment, if you’re not using the Flex framework (I figure I need a familiarity with AS3 first before diving into any abstractions built on it), preloaders must necessarily be written entirely in AS3. From my understanding, preloaders have typically worked in a two different ways: the first was to have the movie stop the timeline on the first frame and display a progress bar while loading the contents of the second frame; after the loading was complete, the playhead was advanced to the next frame. The second technique involved using a Loader to access an external swf, then play that swf once the loading had completed. Both of these could work from a pure AS3 point of view — in fact, the latter should be dead simple. That said, since I’m stubborn, I wanted to do it the *first* way, because it permits you to embed ALL your assets in a single swf. A single swf seems that it would make for a simpler and more elegant deployment (we’ll see if this is the case!). Of course, a pure AS3 preloader using the first technique is much harder. There appear to be two ways of implementing the first technique in AS3 at this point, each of which use an under-documented feature of the Flex SDK in order to work. The first to appear was Keith Peters’ method, which uses the Frame metatag of the Flex SDK. The downside is that method seems to automatically embed in much of the Flex framework unless you do some extra configuration tasks. The second method was authored by Sven Busse (German-language-text) and explained here in English by Lars Gerckens. The Busse method requires you to add a compiler flag that moves your main class (the one being preloaded) to a second frame, but is a little conceptually easier to follow, so that’s the one I’m using for now. That said, the Peters method may end up making re-use simpler (plus you don’t have to remember to set the compiler flag, which I could see being easy to overlook). Now, for some reason, neither of these preloaders work correctly when viewed locally with IE7. I assumed it had something to do with the way IE7 loaded local files, so I didn’t worry about it. Unfortunately, on my server, the behavior changed entirely — now neither browser preloaded correctly; instead, they’d show 100% preloaded before loading could complete and the init method could fire. After four hours of debugging the entirely wrong things (browser cache, client-side issues), I tried uploading it to another server, and a thing of beauty happened — both IE7 and Firefox completed the loading process beautifully. I called it a day and came in this morning to figure out where I went wrong on my work server, thinking it might be a mime type issue. It wasn’t a mime type issue — looks like the swf mime type is, by default, in the mime.types of the Apache 2 distro for CentOS. Unfortunately, mod_deflate was turned ON ( also presumedly by default), and was busily gzipping everything in sight, including swfs. After another thirty minutes of searching, I found the following htaccess directives successfully turned off gzip compression for swf files (it also does a lot of other things, and I haven’t had the time to refine it for just my purposes, so caveat emptor):
SetOutputFilter DEFLATE # Netscape 4.x has some problems... BrowserMatch ^Mozilla/4 gzip-only-text/html # Netscape 4.06-4.08 have some more problems BrowserMatch ^Mozilla/4\.0[678] no-gzip # MSIE masquerades as Netscape, but it is fine BrowserMatch \bMSIE !no-gzip !gzip-only-text/html # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48 # the above regex won't work. You can use the following # workaround to get the desired effect: BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # Don't compress images SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary SetEnvIfNoCase Request_URI \/image\.php no-gzip dont-vary # Also don't compress PDF and Flash-files 17-01-2004 MM SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary SetEnvIfNoCase Request_URI \.swf$ no-gzip dont-vary # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-varyWith this information you should be able to free yourself entirely (I hope) from having to fiddle with code in Flash CS3. This should keep me sane while I wait to get some time to set up the perfect AS3 environment in Linux so I can get back to using vim for editing. UPDATE: gah! After thinking I had the definitive fix to this, I found that my preloaders *still* weren’t working correctly. I spent another 4 hours working on the problem and have apparently fixed it server-wide. At issue was that the mod deflate directives did not seem to work correctly in .htaccess files. I haven’t *fully* confirmed this (I’m happy enough that it’s working on my server), but let me suggest the following fix, which *SO FAR* appears to work for me. If you don’t already have a mod_deflate.conf file in your /etc/httpd/conf.d/ dir (CentOS — on Deb/Ubuntu this is probably in /etc/apache2/conf.d), create one and add the following:
I also want to note that if you’re running something like Fiddler which proxies IE, the preloader does not appear to work either, which seems a fantastic illustration of the Heisenberg Uncertainty principle at work. I truly hope this is the last time I have to mess about just to get a pre-loader to work, but I seriously doubt it will be.SetOutputFilter DEFLATE BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # Don't compress images/flash SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png|swf|flv)$ no-gzip dont-vary # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-vary