Loading an external swf with parameters in the URL

Recently I needed to load an external swf with parameters in the URL (eg. file.swf?foo=bar). The reason was to prevent loading of any cached version of the swf by adding a random number to the url. Seems like a simple enough task, right? Well it kind of is. But not as simple as just using the Loader class which throws a 2035: URL Not Found error. And using URLLoader also doesn’t work, as that throws a 2032: Stream Error. The only solution I could work out was to change the dataFormat property of the URLLoader to “binary” (it is set to “text” by default) load the swf, and then use a Loader’s loadBytes method to load the URLLoader’s data. See my ParamSWFLoader class below as well a simple usage example. Feel free to use it in your own projects. Note it makes us of Robert Penner’s AS3 Signals which you’ll need to download.

/**
 *
 * ParamSWFLoader class
 *
 * Copyright (c) 2010 Ben Kanizay
 * This software is released under the MIT License
 *
 */
package beekay.core.utils {
	import org.osflash.signals.Signal;

	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;

	/**
	 * @author ben.kanizay
	 */
	public class ParamSWFLoader {

		protected var request:URLRequest;
		protected var urlLoader:URLLoader;
		protected var bytesLoader:Loader;

		protected var _loadedContent:DisplayObject;
		public function get loadedContent() : DisplayObject {
			return _loadedContent;
		}

		public var signalError:Signal;
		public var signalProgress:Signal;
		public var signalComplete:Signal;

		public function ParamSWFLoader() {
			this.signalError = new Signal(String);
			this.signalProgress = new Signal(int);
			this.signalComplete = new Signal();
		}

		public function load(url:String) : void {
			this.urlLoader = new URLLoader();
			this.urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			this.request = new URLRequest(url);

			this.urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onLoaderSecurityError, false, 0, true);
			this.urlLoader.addEventListener(IOErrorEvent.IO_ERROR, this.onLoaderIOError, false, 0, true);
			this.urlLoader.addEventListener(ErrorEvent.ERROR, this.onLoaderError, false, 0, true);
			this.urlLoader.addEventListener(ProgressEvent.PROGRESS, this.onURLLoaderProgress, false, 0, true);
			this.urlLoader.addEventListener(Event.COMPLETE, this.onURLLoaderComplete, false, 0, true);

			try {
				this.urlLoader.load(this.request);
			}
			catch (error:Error) {
				this.signalError.dispatch(error.message);
				this.removeURLLoaderListeners();
			}
		}

		protected function onLoaderError(event : ErrorEvent) : void {
			this.signalError.dispatch(event.text);
			this.removeURLLoaderListeners();
		}

		protected function onLoaderSecurityError(event : SecurityErrorEvent) : void {
			this.signalError.dispatch(event.text);
			this.removeURLLoaderListeners();
		}

		protected function onLoaderIOError(event : IOErrorEvent) : void {
			this.signalError.dispatch(event.text);
			this.removeURLLoaderListeners();
		}

		protected function onURLLoaderProgress(event : ProgressEvent) : void {
			var percentLoaded:int = Math.round((event.bytesLoaded/event.bytesTotal)*100);
			this.signalProgress.dispatch(percentLoaded);
		}

		public function removeURLLoaderListeners() : void {
			this.urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onLoaderSecurityError);
			this.urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, this.onLoaderIOError);
			this.urlLoader.removeEventListener(ErrorEvent.ERROR, this.onLoaderError);
			this.urlLoader.removeEventListener(ProgressEvent.PROGRESS, this.onURLLoaderProgress);
			this.urlLoader.removeEventListener(Event.COMPLETE, this.onURLLoaderComplete);
		}

		protected function onURLLoaderComplete(event : Event) : void {
			this.removeURLLoaderListeners();

			this.bytesLoader = new Loader();
			this.bytesLoader.contentLoaderInfo.addEventListener(ErrorEvent.ERROR, this.onLoaderError, false, 0, true);
			this.bytesLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onBytesLoaderComplete, false, 0, true);

			try {
				this.bytesLoader.loadBytes(this.urlLoader.data);
			}
			catch (error:Error) {
				this.signalError.dispatch(error.message);
				this.removeBytesLoaderListeners();
			}
		}

		protected function onBytesLoaderComplete(event : Event) : void {
			this.removeBytesLoaderListeners();
			this._loadedContent = this.bytesLoader.content;
			this.signalComplete.dispatch();
		}

		public function removeBytesLoaderListeners() : void {
			this.bytesLoader.contentLoaderInfo.removeEventListener(ErrorEvent.ERROR, this.onLoaderError);
			this.bytesLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, this.onBytesLoaderComplete);
		}		

	}
}

And a simple usage example:

package {

	import beekay.core.utils.ParamSWFLoader;

	import flash.display.Sprite;

	/**
	 * @author ben.kanizay
	 */
	public class Main extends Sprite {

		protected var swfLoader:ParamSWFLoader;

		public function Main() {
			this.swfLoader = new ParamSWFLoader();
			this.swfLoader.signalError.addOnce(this.onSwfLoaderError);
			this.swfLoader.signalProgress.add(this.onSwfLoaderProgress);
			this.swfLoader.signalComplete.addOnce(this.onSwfLoaderComplete);

			this.swfLoader.load("http://path/to/content.swf?cacheBlocker=" + parseInt(String(Math.random()*1000)));
		}

		protected function onSwfLoaderError(error:String) : void {
			trace("ERROR: " + error);
		}

		protected function onSwfLoaderProgress(percent:int) : void {
			trace(percent + "% LOADED");
		}

		protected function onSwfLoaderComplete() : void {
			trace("DONE!");
			this.swfLoader.signalProgress.remove(this.onSwfLoaderProgress);
			this.addChild(this.swfLoader.loadedContent);
		}

	}
}

3 comment(s)

Track this comments via RSS 2.0 feed. Feel free to post the comment, or trackback from your web site.

  1. Apr 13, 2010 12:22 Jessy Brown said:

    hmm,useful information.. I have learned it LOL

  2. May 20, 2010 0:14 Stephen Woolcock said:

    Hey Ben,
    You should be able to just use the data property of the URLRequest object to do this. Mind you, I haven’t tested in a live environment to see if cache bypassing works, but in theory it should.

    —–

    var params:URLVariables = new URLVariables();
    params.noCache = Math.random();

    var request:URLRequest = new URLRequest(”http://localhost/redshift/data/swf/game.swf”);
    request.data = params;
    request.method = URLRequestMethod.GET;

    var loader:Loader = new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
    loader.load(request);

    function onLoadComplete (e:Event) : void
    {
    trace(”Load complete”);
    var p:Object = loader.contentLoaderInfo.parameters;
    for (var i:String in p)
    trace(i, “=”, p[i]); // output: noCache = 0.8092844560742378
    }

  3. May 20, 2010 7:53 Ben said:

    Cheers Stephen. Haven’t tried that way for cache bypass. Might give it a run and see.

Comment on this post