Skip to content
May 21 2010 / alecmce

[Embed(source="asset.swf")] Gotcha (and Workaround)

It’s been a long-time without a post. Part of the reason for that has been starting work at a new job (which involves a commute), and part has been that as part of my new job, I was actually encouraged to spend time playing World of Warcraft. To me, that’s like taking a crowbar to Pandora’s Box and having a peek inside. I learned quite a lot, but have also played just a few too many Warsong Gulches.

Back to work, and I was doing a little prototyping this evening, when I came across a familiar problem: In AS3 we can use

[Embed(source="asset.swf", symbol="symbol")]
private var symbolClass:Class;

var symbol:MovieClip = new symbolClass();

to embed a symbol from an art SWF in what is probably a code-built SWF. That’s great, but what if you want to embed an entire SWF?

[Embed(source="asset.swf")]
private var assetClass:Class;

var asset:MovieClip = new assetClass();

looks like it should do the trick, but you can’t access any of the information within the asset. That’s a real pain, the reason for which is pretty convoluted. I remembered working around this problem in the past, and happily managed to unearth a long-forgotten treasure in my codebase, which I thought I’d share (having rapidly refactored it to use as3-signals, naturally).

package com.alecmce.util
{
	import org.osflash.signals.Signal;

	import mx.core.MovieClipAsset;

	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.events.Event;

	public class UnpackEmbed
	{
		private var _ready:Signal;

		private var _asset:MovieClipAsset;
		private var _content:MovieClip;

		public function UnpackEmbed(assetClass:Class)
		{
			_asset = new assetClass();
			_ready = new Signal(UnpackEmbed);

			var loader:Loader = Loader(_asset.getChildAt(0));
			var info:LoaderInfo = loader.contentLoaderInfo;
			info.addEventListener(Event.COMPLETE, onLoadComplete);
		}

		private function onLoadComplete(event:Event):void
		{
			var info:LoaderInfo = LoaderInfo(event.target);
			info.removeEventListener(Event.COMPLETE, onLoadComplete);

			_content = MovieClip(info.loader.content);
			_ready.dispatch(this);
		}

		public function get content():MovieClip
		{
			return _content;
		}

		public function get ready():Signal
		{
			return _ready;
		}

		public function get asset():MovieClipAsset
		{
			return _asset;
		}
	}
}

When you embed a SWF in this way then instantiate it, Flash somehow conspires to create a MovieClipAsset with a Loader inside, which will be ‘loading’ the already-embedded content. The content is not available immediately (it may be sometimes, I have encountered cases where it was not), so you have to wait for an Event.COMPLETE to be fired before you can access it. This class exposes a signal that informs you when the content is ready. It could probably be more rigorous, such as including an isComplete flag, but it serves my purposes, when used in the following manner:

[Embed(source="asset.swf")]
private var assetClass:Class;

asset = new UnpackEmbed(assetClass);
asset.ready.addOnce(onAssetReady);

private function onAssetReady(asset:UnpackEmbed):void
{
	// now we can access the asset.content!
}
  • Anonymous

    Cool, this will come in handy!

    One minor optimization: on line 24 you (probably inadvertently) use your “get asset” function by typing “asset” rather than directly getting the field by typing “_asset”.

    • http://alecmce.com Alec McEachran

      Thanks Jackson, yeah, that was definitely inadvertent. :)

  • jacksondunstan

    Cool, this will come in handy!

    One minor optimization: on line 24 you (probably inadvertently) use your “get asset” function by typing “asset” rather than directly getting the field by typing “_asset”.

  • http://alecmce.com alecmce

    Thanks Jackson, yeah, that was definitely inadvertent. :)

  • Alex Berger

    I am not sure if this is a related question, but it is a problem that I am having.

    I have a gigantic .fla with a lot of class-linked movieclips and bitmaps (just sitting in the library waiting to be accessed programmatically.

    The file became so big, or contained so many Library assets or class files, that Flash wouldn’t compile.

    So I extracted all the library assets out into their own swfs and used the Loader class to load all the swfs back into the main file… and then used (oncomplete) event.target,applicationDomain.getDefinition({classname}) to access my, now, externalized library items.

    This worked, but kept crashing the browser at run time.

    What I would really like to do, is to re-import the swfs (that I externalized) into my main library, export them in first frame with class identifiers, and access their library assets as I was doing with applicationDomain.getDefiniton.

    Is that possible with your or some other technique?

    • http://alecmce.com Alec McEachran

      I’m not sure this problem is related to the mechanism by which you get your assets into Flash. The only time I’ve ever seen Flash crash the browser reliably is when the assets you’re loading unpack to use more memory than there is in the browser heap. The solution to that is… use different assets.

  • Fabriciodezain

    I liked the solution. Now, I can access the library of the swf?How? Thank you for attention! ^^

    • http://alecmce.com Alec McEachran

      You need to export library assets for ActionScript. There are plenty of tutorials out there that explain how to do this. You should probably wait until the onAssetReady method before trying to access library elements though.

  • http://www.seven-seventeen.com Josh

    Hey Alec,

    Thanks for the great post – it was amazingly helpful, I have a quick question though:

    The project I’m working on uses the embedded SWF as art primarily, but does have some text fields. The font and the text used in these text fields changes based on user choices so, I’m trying to find a way to Embed fonts for the text fields in the Embedded SWF. I’m familiar with the [Embed] tag and setting embedAsCFF=”false” but the fonts still aren’t embedding. Any chance you’ve done this? Maybe you have a code sample?

    Many thanks for any help,

    Josh

  • Pingback: Embed SWF und Anzeige-Problem? - Flashforum

  • Gergely Rossel

    Very good idea! Thank you very much, it is really useful.

    I made slight changes, I derived the class from EventDispatcher, so I could eliminate Signal dependency.

    Best regards,
    Gergely Rossel.

  • Alex Greentown

    In the line 5  asset.ready.addOnce(onAssetReady);
    I found that _ready = new Signal()
    probably you have the Signal class description in some other posts.
    Anyway, I will make it my way, but the method is very usefull, I didnt know about it
    Thanks for the tip !!!