File downloading with Adobe AIR using HTML and jQuery
comments (16) Views: 8,710
If you're developing an AIR application using HTML and JavaScript, you may eventually have the need to download a file from a remote web server to the user's local machine. AIR gives you the power to do this, with just a few lines of code. This article will show you the code needed to download a specific file from a remote URL and save it to the local file system. As always, your first step is to create a new AIR project, or import an existing AIR project. If you'd rather import a project, you can download the full source for this article. While creating your new project, make sure to add the AIRAliases, and AIRIntrospector files, as well as the jQuery library. The demo version of this application uses jQuery 1.4.2, but ColdFusion Builder only ships with 1.3.2. It should work without upgrading, but it's always better to have the latest and greatest. Let's get started.
- Open the HTML file for your project. If you're importing the source from this article, the file is named DownloadFile.html
-
Add the following lines of code to the head of your document.
- The first few lines add some basic styling to the application. Nothing fancy, just enough to keep stuff away from the edges.
- The fifth and sixth lines include our AIR specific code: the AIRAliases file (contains shortcuts we'll use later), and the AIRIntrospector, essentially Firebug for AIR applications.
- Line 7 includes jQuery, adjust the filename to the version you're using in your project.
- Finally, line 8 includes Application.js. The file name is nothing special, but it helps to indicate that this file contains your main code for the application.
-
Add the following lines of code to the body of your document
- Here we're simply adding some standard form controls, along with their associated labels. One for the file URL, one to allow downlocation selection, and one for the submit button.
- That's all there is to the interface. Go ahead and run the application and see what you get.
- If your application is behaving unexpectedly, be patient. We'll get to that in the next section.
In this project we're going to give you, the user, the chance to select where you want the file to end up. One of the excellent things about AIR is that the same AIR file can be installed on Windows, Mac, and Linux. Adobe has given us several built in properties of the File object which correspond to specfic locations on your machine; even though the locations might not exist in your operating system. These properties are applicationDirectory: where the app itself gets installed; applicationStorageDirectory: where custom data for the app is stored; and desktopDirectory: the user's desktop.
- We've written the HTML code for our interface, now let's give this app it's functionality. Let's create a file in our /lib/ directory, we'll call it Application.js. If the file already exists, simply open it.
- In that file place the following code. This helps keep our simple application organized. Larger, more complex applications will benefit from a more regimented structure, but for this example, everything in one file is fine.
-
The first thing we need to do is to add a binding to the form element in the HTML page. We want to intercept it's submision and do something with the values that it will contain. Add the following lines of code directly under the line reading /* INTERFACE BINDINGS */ and let's review 3 key points.
- Line 1 is simply a reference to the form itself. We'll be reusing that, so it makes sense to save it off. It has a dollar sign in front of it to indicate that the variable contains a jQuery object.
- Line 5: If you've never seen preventDefault being used, or you're just used to issuing a "return false" command to stop form submissions or click events, then you should read this article from Douglas Neiner about the practice. jQuery's anonymous function allows us to pass "e", or the event that we just triggered, through to the body of the function so that we can take advantage of built-in methods of the event object.
- Line 15: The downloadFile function will do just what you think it should do. We pass the remote URL, along with which download location the user selected: desktop, or storage, directory.
-
Finally, let's add our downloadFile function, the workhorse of this demo application, and walk through the code. Paste, or type, the following code directly below the line reading /* FUNCTION DEFINITIONS */.
- Line 3: The first thing we're doing is grabbing the filename from the remote URL. This is optional...you can use the filename as it exists remotely, or you can create a new filename client side. It's up to you.
- Lines 5-6: This is where the user's choice of download location comes into play. We determine where they want to store the file, then use the built in method of the File object, resolvePath, to create an OS specific file path.
- Line 7: Creates new URLStream, which allows you to pull down the bits and bytes of the remote URL to the file system.
- Line 8: Creates an event listener which fires when the bits and bytes are available on the local machine. Note that they're not technically "saved", until the callback function fires.
- Lines 9: When it comes down to it, all files are made up of bytes. Here we create a new ByteArray, essentially an empty vessel, to receive the contents of the remote file.
- Line 10: Does the pouring of the bytes into the empty ByteArray container.
- Lines 11-14: Just like we had to create a URLStream to load a remote URL, we create a new FileStream to access a local URL. Then we open it, save the contents of the ByteArray, and close the file
- Put it all together and you've got a file downloader written in HTML and JavaScript, powered by Adobe AIR.
- It's worth noting that this specific implementation is looking for a specific file to download. AIR has to know what sort of file you're expecting so that it can give it the correct file name and extension.
Hope you enjoyed this article and don't forget to download the source, including the actual AIR file.
If this article was interesting, or helpful, or even wrong, please consider leaving a comment, or buying something from my wishlist. It's appreciated!
Great article. Thanks. How would you create a progress bar to go with the download.
Jason - October 20, 2010 09:40 pm
Great question Jason. In researching the approach I decided to write up a blog post on how to do just that. Please check it out Downloading Files with Adobe AIR, HTML and JS Part 2. Adding a Progress Bar with Canvas. Let me know if it answers your question.
andy matthews - October 21, 2010 01:43 pm
Your blog post references lib/downloadfile/Application.js but it has since been placed into lib/Application.js. I'm getting ReferenceError: Can't find variable: $
Phillip Senn - October 25, 2010 01:16 pm
Phillip...I'll have to look into it. If that's the case then you should be able to change the reference to Application.js. If you're getting an error about variable: $, that means it can't find jQuery. Add a reference to jQuery in the lib folder and try again.
andy matthews - October 25, 2010 05:01 pm
Hey, Great article, but maybe its nice to mention that you can check the progress of a download with the following code: stream.addEventListener( air.ProgressEvent.PROGRESS, function(ev) { if(ev.bytesTotal!=0) { progress = ev.bytesLoaded/ev.bytesTotal*100+"%"; } else { progress = "0%"; } });
Roelof - November 24, 2010 02:37 pm
Thanks Roelof. The actual application does have a progress bar using the canvas element. You can see that in the finished application.
andy matthews - November 24, 2010 03:54 pm
I think where you say fileStream.openAsync(localFile you should be using the e.target instead. (Or e.target.data or something), because the event listener shouldn't know about localFile from the function. http://help.adobe.com/en_US/AIR/1.5/devappshtml/WS5b3ccc516d4fbf351e63e3d118666ade46-7cb1.html
Phillip Senn - November 29, 2010 01:29 pm
Thanks Phillip. I'll check into that method instead.
andy matthews - November 29, 2010 05:21 pm
This is a bit off the topic but what if you wanted to create a file(xml or json) then change the extension so that only your app can read it. How do you get the Os to associate such file to your app?
Thompson - December 22, 2011 01:12 am
That's a really good question. It looks like you CAN associate a file extension with your app. Take a look at this article on the Adobe website.
andy matthews - December 22, 2011 07:57 pm
Thank you very much. I have another off the topic question. Please how can I make the downloads reasume supported?
Thompson - December 23, 2011 11:19 am
I didn't actually think this would be possible, but it seems as if it is. Take a look at these two blog posts. They're using Flex specifically, but you should be able to make them work for JavaScript:
Resume download in AIR via SOCKET
Resumable Downloads with AIR
Andy matthews - December 23, 2011 07:21 pm
Hey ! This is great. Thank you very much for sharing !
Julien - April 13, 2012 03:03 pm
Hi, this is really good article. I have a stupid question. Is it possible to download a file using the file directory, not file URL?
Bob - October 17, 2012 05:42 pm
Bob, I haven't tested that, but I don't think so. The difference between the two is that file directory is for local files, where as file url is for remote files.
andy matthews - October 25, 2012 11:54 am
Thank you
Fatih - January 16, 2013 01:35 am