I spent Saturday evening wrestling with Flash’s file download capability and thought I’d share a couple of the subtleties I encountered. I’m relatively new to Flash programming (but hey, it’s simply ECMA-262 with excellent visual capabilities), and I’m one of those guys that believes in using the right tool for the job. For what I was trying to accomplish, Flash fits the bill. I’m also one of those guys that thumps on a tool until I subvert it to my purposes. What follows is a couple of items I learned from a Saturday evening in front of the TV with laptop regarding the Flash FileReference object.
The documentation on the FileReference object is fairly sparse and I’m sure I’m not the first to encounter these issues but I thought I’d post a couple of the issues I encountered.
#1 – Variable scoping – not so obvious
The biggest gotcha is that the FileReference instance needs to be declared at a level where it doesn’t go out of scope before the d/l completes. The first several times I tested the download feature, the trace window showed the download progress but the file wasn’t being written because the fileref object had gone out of scope. I had it buried in an event handler than ran to completion, *presumably* was garbage collected, and killed the download. I am used to .NET and was expecting an exception to be thrown and caught in the trace window.
#2 - File Existence – This is fairly obvious
The file your downloading needs to exist at the source. Otherwise, nothing happens.
Following are snippets of code that helped address my file download needs:
#3 – Alerts need to be added to the library before they can be used. The tool tells you this, but it’s a little odd IMO. Essentially, you need to drop an instance of an Alert onto the stage to add it to the library. You can then delete it from the stage (but it’s still in the movie library).
Relevant Code Snippets
This code lives in an “Actions” layer in keyframe 1 of the Flash movie timeline.
import flash.net.FileReference;
//pbSaving is a progress bar
pbSaving.visible = false;
//A simple “Cancel” button that appears when a download is active
btnCancel.visible = false;
//File Download – **** Put these variables where they won’t go out of scope ****
var listener:Object = new Object();
var fileRef:FileReference = new FileReference();
//Event listenter object — use this to trap/handle events
fileRef.addListener(listener);
var url:String ;
/*
Cancel download button – this is useful in situations where the user has a slow
connection, a big file, or both
*/
//Handle the onPress for the Cancel button
btnCancel.onPress = function() {
fileRef.cancel();
pbSaving.visible=false;
this.visible=false;
};
//Invoked when the “Download” button gets pressed
btnDownload.onPress = function() {
//url is declared at global scope for simplicity
url = “(http://www.somesite.com/myfiles/afile.txt“);
if(!fileRef.download(url, “afile.txt”) {
trace(“dialog box failed to open.”);
}
};
//This handler isinvoked after the user selects the file location for the download
listener.onSelect = function(file:FileReference):Void {
//Pause the download – not required but the video gets pretty jerky IMO
//FLVPlaybackVideo is an instance of FLVPlayback on the stage
FLVPlaybackVideo.pause();
btnCancel.visible = true;
pbSaving.visible = true;
}
//This handler is invoked if the user presses the “Cancel” button to
//interrupt the download
listener.onCancel = function(file:FileReference):Void {
btnCancel.visible = false;
pbSaving.visible = false;
//Resume playback
FLVPlaybackVideo.play();
}
listener.onOpen = function(file:FileReference):Void {
btnCancel.visible = true;
pbSaving.visible = true;
}
//An example of a manual update of the “Saving” progress bar
listener.onProgress = function(file:FileReference, bytesLoaded:Number, bytesTotal:Number):Void {
pbSaving.setProgress(bytesLoaded, bytesTotal);
}
//Handler invoked when the file download is complete
listener.onComplete = function(file:FileReference):Void {
btnCancel.visible = false;
pbSaving.visible = false;
//Resume playing
FLVPlaybackVideo.play();
}
//Handle HTTP errors
listener.onHTTPError = function(file:FileReference, httpError:Number):Void {
/*
Use the Component viewer to land an alert on the stage and add it to the movie library
then delete the instance so it’s not on the stage (but is still in the library).
Seems a little quirky but it works.
*/
Alert.show(“HTTP error encountered in downloading ” + file.name + “: ” + httpError.toString(), _global.appName , Alert.OK, this);
}
//Security error handler
listener.onSecurityError = function(file:FileReference, errorString:String):Void {
Alert.show(“Security error encountered in downloading ” + file.name + “: ” + errorString, _global.appName , Alert.OK, this);
trace(“onSecurityError: ” + file.name + ” errorString: ” + errorString);
}
//IOError handler
listener.onIOError = function(file:FileReference):Void {
//See previous note regarding alerts
Alert.show(“Encountered a problem in downloading ” + file.name, _global.appName , Alert.OK, this);
pbSaving.visible = false;
}