Loading in local external assets into an Air app

I’ve recently been tasked with turning an existing Flash app (that is to say, a self contained Windows EXE/Mac App) into an Air app. The original was only meant to run locally. It was never meant to be hosted on a web server. This module depends on loading in lots of external XML docs and images when you navigate to different sections. When loading in an XML doc, the code looks something like this:

// make the URLLoader that'll load in XML doc
var _l:URLLoader = new URLLoader(new URLRequest(_url));
 
// add a listener to use when the XML doc has loaded
// The xmlLoaded() method actually creates the XML object
_l.addEventListener(Event.COMPLETE, xmlLoaded)
 
// load in an XML doc named "myxml.xml" located in the
// "swf_assets" folder that's next to the SWF
_l.load(new URLRequest("swf_assets/myxml.xml"))

That should look familiar to you if you’ve loaded in an external XML doc before. But this doesn’t work with an Air app. Why? You don’t package external files with an Air app like you do with a SWF. So you need to handle finding external files differently with Air. It goes a little something like this:

// the File object is used to find the location of the
// XML doc we want to load in
var file:File = File.documentsDirectory.resolvePath("air_app_assets/myxml.xml"); 
 
// Pass the file.url property to the URLRequest constructor
var _l:URLLoader = new URLLoader(new URLRequest(file.url));
_l.addEventListener(Event.COMPLETE, xmlLoaded)

What that File.documentsDirectory.resolvePath business is doing is telling the Air app to go to the computer’s Documents directory, then dig into the “air_app_assets” folder to find the “myxml.xml” doc. The key here is that Air will know where the Documents folder is. It’s different on OS X vs. Windows vs. Linux. We just need to make sure that the “air_app_assets” folder lives in the Documents folder.

This isn’t an ideal solution. Had I known that this SWF was going to turn into an Air app, I would have set things up a lot differently. But at this point it’s not worth the trouble to deal with turning a TON of XML docs into a database.

The same principles used above will work for loading external images into your Air app. The key remains using the File class to tell Air where to find the files you want to load in. We can’t just pass in folder and file names when creating new URLRequest instances.

It took way too long to figure this out. I originally found a more complicated way to do this. It went like this:

// Same as before...
var file:File = File.documentsDirectory.resolvePath("air_app_assets/myxml.xml"); 
 
// We're going to use a FileStream object to load in the XML doc
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
 
// Use the FileStream.readUTFBytes() method to write the myxml.xml data
// directly to a new XML object
var _xml:XML = new XML(fileStream.readUTFBytes(fileStream.bytesAvailable)); 
fileStream.close();

That worked and I thought it was the only way to handle loading in external assets that lived on the user’s hard drive. But that’s messier and I like the first method better.

I’m new to this Air thing. Maybe method two is better. I really don’t know. If someone has a real answer and can explain it, I’d love to hear!

Flash-like effects without Flash, might suck.

The Macheist nanobundle is up, and the site has some Flash-like elements created without Flash. When viewed in Safari 4 on my Mac, everything probably looks as intended. But there are some issues with trying to create these eye-candy effects without Flash.

  • It causes some noticeable lag in the browser. These pieces of eye candy would be no sweat for Flash, but it’s causing Safari to run a little slow, especially when scrolling on the page.
  • This because it’s really, REALLY hogging the CPU. And what for? A scroller that shows what people are saying about Macheist on Twitter. And a subtle pulsing glow under the selected product.
  • The initial draw-in effect, where these dish covers are pulled off of the products only shows in Safari, not Firefox. I’m not going to test in Opera. And I’m sure they don’t care how it looks on Windows browsers. And that effect kills the CPU and doesn’t look very smooth.

Look, if you want to do eye-candy stuff, just use Flash. It’s better in every way for this kind of thing. If you hate Flash, why try to mimic what it can do if you are going to come up way short? I’m sure the development time to make this was considerably longer than if it had been done in Flash, too. I really don’t get it.

As an added bonus, the play/pause/scrub controls on the pop up video player didn’t work for me.

I will say that they animated gears that show up when processing the order look very slick.

Oh, but you should grab the free bundle while you can. If only for Write Room.

Compiling SWFs from TextMate with the Flex SDK

I finally feel like I’m all growds up.

Perhaps some details about this transition will follow in the coming days. But let me just say that this is the post that finally got me up and running with the Flex 3.3 SDK and TextMate. I’m not sure how often I’ll use this method. It’s way too soon to tell one way or another. I’m only now trying to figure out what Flex can do compared to Flash. My impression is that Flex isn’t as adept at doing totally custom visual experiences, but I could very well be totally wrong about that.

Two quick notes:

  • I couldn’t figure out why the flashlog.txt output wasn’t getting updated each time I compiled the SWF. Turns out I simply wasn’t opening the SWF after compiling it. Gotta open the SWF to generate the output text!

  • Which leads me to wonder, from TextMate can I quickly compile the SWF and open it in the Flash Player right away?

ActionScript TextFormat.font values

One thing I have to do a lot with ActionScript 3 is make TextField instances at run time that use something other than the default font. One way that I’ll do that is like this:

// make a new TextFormat object and set its "font" property
var myFormat:TextFormat = new TextFormat();
myFormat.font = "Arial";
 
// then make the TextField and apply the TextFormat to it
var tf:TextField = new TextField();
tf.defaultTextFormat = myFormat;

(This doesn’t deal with actually making sure that the font you want to use is embedded in the movie, but that’s another story.)

One part of this that’s been a bit of a mystery to me in some cases is exactly what to set as the TextFormat.font property. And, as you’ll see, there’s good reason to be a little confused, depending on what font you want to use. What you see in the CHARACTER portion of Flash’s PROPERTIES panel doesn’t always match what you need to type in as the TextFormat.font value. For example, if you want to use the following font:

Arial Regular

You need to type the following:

myFormat.font = "Arial"

That’s fairly straightforward, I guess. This one is a little less straightforward:

Meta Thin

…and the code you need to type to Flash:

myFormat.font = "Meta-Thin"

Where did that hyphen come from that goes betwee “Meta” and “Thin”? And how would I know I need to insert when, if I wanted to use Arial Bold, I’d simply type:

myFormat.font = "Arial Bold"

There’s no hyphen in that one. Mysterious.

Even worse, check this one out. Suppose you want to use this specific style of The Sans:

Thesans Sansplain

Guess what name you need to plug into the TextFormat.font property…

myFormat.font = "TheSans Plain"

Hmmm… How in the hell would you ever figure that out? And is there any logic here? And where do I find the string to type in for the TextFormat.font property?

The Solution

Turns out, there is an easy way to figure out exactly what to type in for the TextFormat.font property. It’s a bit of a hack, but it gets the job done. The process goes like this:

  1. Make a dynamic text field in the Flash authoring tool and set its font to the font name you are trying to figure out.
  2. Give that dynamic text field an instance name (let’s use “myField” in this example)
  3. Then type this code into the ActionScript panel:
trace(myField.getTextFormat().font)

That’s it. When you test the movie, the Output panel will print out the ActionScript version of the font name, which is exactly what we are looking for.

FLV bitrate capped?

I’ve got this beautiful QuickTime movie I need to convert to an FLV so that I can embed it into the Flash timeline. The source movie is, like I said, beautiful. 500x500px, 2 seconds long, and a whopping 15.5MB. With a file size like that, you’d expect it to look good. Also, for what it’s worth, the clip has an alpha channel baked into it and was created in some sort of 3D program (Maya or 3DS Max, I think).

Problem is, the FLVs that Adobe Media Encoder is turning out look pretty much like crap.

So I thought I’d turn up the export settings “to eleven” across the board to increase the quality of the FLV it gives me. But it doesn’t work. In fact, once I get to a certain point, the file size (and quality) seems to be capped. Even with all of the settings turned up as high as possible, the biggest FLV I get is a puny 772KB. And, the weird thing is, even if I turn down the settings (to 5 across the board, for example), I still get the same 772KB FLV. As you’d expect, going from 15.5MB to 772KB leads to some substantial loss in quality.

What the hell is going on? What’s with this cap on quality? It seems pretty clear that the FLV encoder is saying “this quality is good enough for you and I refuse to make anything better.” Grrr… This would be fine if I didn’t need to encode the alpha channel and embed the FLV directly onto the timeline. But I do. And I seem to be stuck with these fairly low-quality FLVs.

Unless there is another method to get this sequence of frames from the QuickTime movie embedded into the Flash timeline. I guess I’ll look into that next.

A-ha! QuickTime Pro will let me export a clip as an image sequence. Perfect! And this actually solves another weird issue I was having (that I won’t get into here). But it does add a new problem: each PNG that’s part of the image sequence seems to be of a different gamma setting than the source QuickTime clip. So either there’s a setting I need to adjust when exporting or I’m going to have to batch process these PNGs in Photoshop.

So, the trick to fix the color issue is to open the files in PS and then Save for Web. That removes the color profile info that QT attaches to each PNG. I’m good to go now.

Error #2121 when loading external SWF

I’m running into an issue that goes a little something like this:

  • I have an external SWF that I’m loading into another parent SWF
  • The external SWF is simply a still image I created from a PNG using Fireworks CS3
  • I package up the parent SWF and external SWF and send it to another computer
  • When loading the external SWF with a Loader, I get the following message when trying to access the loader.contentLoaderInfo.content property within the Loader’s Event.INIT listener:

SecurityError: Error #2121: Security sandbox violation:
LoaderInfo.content: file:///Users/erikhansen/Desktop/SWF Loader Test/swf_loader.swf
cannot access file:///Users/erikhansen/Desktop/SWF Loader Test/from_fireworks.swf.
This may be worked around by calling Security.allowDomain.

Some more info that I know:

  • This works just fine when posted to a web server
  • This will also work without throwing an error if I create the external SWF with Flash (which will just make the whole process of making SWFs from PNGs even a bigger pain in the ass than it already is)
  • If I want, I could just add the Loader directly to the stage, but there are times that I need access to the loader.contentLoaderInfo.content property

So I’m trying to figure out a way around this problem. It usually isn’t a problem at all since, like I said, it works fine when being loaded from a web server. But it is a problem when I send a project to a client and they can’t view it on their computer. Hmm…

No solution yet. Maybe you know something I don’t.

Hide the Flash CS4 pixel grid

You know how when you zoom in far enough in Flash CS4 that tiny “pixel grid” shows up? It’s a nice feature, but I don’t always want to see it. Turns out getting it to go away is as simple as deselecting: View > Snapping > Snap to Pixels

It took me more than 30 seconds to figure it out so I thought I’d share.

Adobe Error 150:30 (and how to fix it) a.k.a. I Hate Adobe – Reason 34

NOTE Check out the bottom of this post for some updates to possible solutions, including how to fix this problem under OS X 10.7 Lion

I fired up Photoshop today and was greeted by this message:

Same thing when I started Flash. Awesome… Keep in mind my Mac has been on for days and hasn’t had any other problems. I really hadn’t done anything strange to break something. And I’m sure I’d used an Adobe product yesterday.

Rebooting, of course, didn’t fix anything.

Looking for help on Adobe’s forum didn’t help.

But Google did.

I found a page that basically explained how to hack around Adobe’s activation. I didn’t need to go that far, since I actually have a legal license. But part of the “how to steal CS4″ post did help. All I had to do was get Adobe’s Licensing Repair tool here.

I ran that and it worked immediately. No reboot needed. I’m thinking I got lucky.

I just noticed that this process dumped a folder named “AdobeLicensingFilesBackup” into my Home folder. So, be aware of that.

UPDATE: Saturday, August 1, 2009

I see that this simply isn’t working for some people, but it looks like it still works for others. I don’t have an explanation for this. All I know is that it worked for me so I thought I’d share it with the world.

I know that a fair number of people are landing on this page every day and would love to hear from those who it does work for, so I know that this tip is still useful.

UPDATE: Monday, August 31, 2009 – Try deleting the FLEXnet Publisher folder

One of the replies below, from Simon, pointed out that you might need to delete the following folder for things to work again:

/Library/Preferences/FLEXnet Publisher

That’s worked for a few people out there, so give it a shot before you throw in the towel.

UPDATE: Wednesday, September 9, 2009

From Rob B. in the comments below:

The Flexnet Publisher folder must be deleted. Not JUST the flexnet folder inside. ALONG WITH THIS the Adobe PCD.cache file must be deleted also. It is located in library/application support/adobe/adobe PCD/ cache/ cache.db

UPDATE: Monday, May 16, 2011 – Works with CS5 and CS5.5, too

Based on some comments below, this fix works for CS5 and the newly released CS5.5 as well.

UPDATE: Friday, October 7, 2011 – The Lion Fix

In the comments, codeman38 was the first to explain how to run the License Recovery app under Lion:

  1. Mount the .dmg for the license recovery app.
  2. Open Terminal.
  3. Run the following two commands:

    cd /Volumes/LicenseRecovery\ 11.6.1/LicenseRecovery/
    sudo python LicenseRecover.py