AIR: How to save locally a resource from Web

I am working on a very, very cool AIR project. I can’t say much about it for now, but in a couple of weeks I hope it will be released, and then I will blog about it. Anyway, while working on this project I had to implement different work flows revolving around online/offline status. One thing you often want to do in an AIR application is: save resources from the web to the local machine, either to make them available to the application even when a network connection isn’t available or just to optimize bandwidth usage.

That’s what this article is about. I will show you a simple snippet of code that just does the job. Here is the exported AIR project (download it, and you can import the archive using Import > Flex Builder > Flex Project) and here is the the application code:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
    <mx:Script>
        <![CDATA[
        import mx.controls.Alert;

        /**
         * loader object used to load content from web
         */
        private var loader:URLLoader = new URLLoader();

        /**
         * This function gets called when the application was loaded.
         * Initialize the loader object.
         */
        private function init():void {
            //we want to download images and other binary resources, 
            //so I overwrite the default value text to Binary
            loader.dataFormat = URLLoaderDataFormat.BINARY;
            //attach the event listeneri for load event and errors event
            loader.addEventListener(Event.COMPLETE, onLoad);
            loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
            loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
        }

        /**
         * This is the click handler for the button in page.
         * Just triger the load and disable the button so no other 
         * request can be sent while it is already running one.
         */
        private function saveResource():void {
            loader.load(new URLRequest(resURL.text));
            btn.enabled = false;
        }

        /**
         * This function gets called when the resource was loaded.
         * We just extract the name of the resource and call the saveLocally() function
         * to write the object on the local machine.
         */
        private function onLoad(event:Event):void {
            btn.enabled = true; //enable the button so we can send another request.
            var fileName:String = new String(resURL.text).split("/").pop();
            //call the saveLocally function; loader.data has the bytes of the loaded resource
            saveLocally(fileName, loader.data);
        } 

        /**
         * Error handler for loader object. 
         * I just display the error message and enable the button for new requests.
         */
        private function onError(event:ErrorEvent):void {
            btn.enabled = true;
            Alert.show(event.text, "Error");
        } 

        /**
         * This function does the actual saving.
         * @param file name to be used for saving
         * @param bytes to be written
         */
        private function saveLocally(fileName:String, data:ByteArray):void {
            //create a file under the application storage directory using the filename argument
            var file:File = File.applicationStorageDirectory.resolvePath(fileName);
            if (file.exists)
                file.deleteFile(); //delete it if exists
            //create a file stream to be able to write the content of the file    
            var fileStream:FileStream = new FileStream();
            //open the file stream and set for Write
            fileStream.open(file, FileMode.WRITE);
            //writes the bytes
            fileStream.writeBytes(data, 0, data.length);
            //close the stream
            fileStream.close();
            //display the path of the saved resources    
            showLocalPath.text = file.nativePath;
        }
        ]]>
    </mx:Script>
    <mx:VBox width="820" x="10" height="200" y="10">

        <mx:Label text="Save a web resource locally"  fontSize="26"/>
        <mx:Label text="Enter a resource URL such as http://mysite/image.jpg" />
        <mx:HBox>
            <mx:TextInput id="resURL" text=""  width="600"/>
            <mx:Button id="btn" click="saveResource()" label="Save locally" />
        </mx:HBox>
        <mx:Label id="showLocalPath" />
    </mx:VBox>
</mx:WindowedApplication>

Here is an explanation of what I did:

  • To getting the resource from the web, I use URLLoader. This object has a property that I can set to control how the resource is loaded: dataFormat. Since I want to download binary objects such as images and movies, I set this property to URLLoaderDataFormat.BINARY. Next, I attach some functions to my loader for Complete and Error events.
  • When the resource is loaded, the onLoad function gets called and I can use the data loaded to create a file locally. I have access to loaded data using the loader.data property. This property gives me a ByteArray.
  • Having the data, I can write the file using the AIR API. I use File.applicationStorageDirectory.resolvePath(“file name”) to create a file in the Application storage folder. I write to this file using a FileStream.
  • The rest of the code is just a simple UI: a text input to let the user to enter the URL for the resources, a button to execute the code, and a label that displays the path to the saved file.

6 thoughts on “AIR: How to save locally a resource from Web

  1. Pingback: Storing data locally in AIR : Mihai CORLAN

  2. hi!!!!!
    I already have 100 video files (.swf format) which I want to play in the player(made in Flex Builder3)How can I store these videos files locally in SQLite and play them from there.After that how to bundle my AIR application and database together to distribute my application to users.Actually,I want to make completely offline application for users having no net connection. I will be thankful if u would give me code for this.

  3. Pingback: Saving remote images locally in an AIR app

  4. Hi, very nice article, but you don’t say how to show the files after saving lol.
    I’m making mobile air app that caches images localy.
    I save the ByteArrays as you say, but the files aren’t readable as if it’s not an image file(even in my computer).
    I’m using an extended ContentCache to control it, and ContentCache uses a Loader, not an URLLoader, so I can’t change the dataFormat to binary. Do you think this may be the problem?
    Thanks!

  5. Well, I just tryed and if I use URLLoader to save the ByteArray data, it works.
    My problem now is how do I save the image loaded by I Loader class.
    Any idea?

Leave a Reply

Your email address will not be published. Required fields are marked *