Storing data locally in AIR

If someone asked me how to store data locally in AIR (on the user’s machine), I think this would be my answer in short:

  1. Store data in the SQLite database
  2. Store ActionScript objects in files
  3. Store assets in files
  4. Store ActionScript objects in the encrypted local store

Let’s talk about each one and see how you can use it.

Store data in the SQLite database

Every AIR application has access to an embedded SQL database (SQLite to be precise). This database supports (almost :D) ACID transactions, implements most of SQL-92, and more importantly, you don’t have to configure a thing to use it. It is there and if you need it, you can use it. All the database information is stored in a single file.

If you are not sure why you would use this feature, I’ll give you an example. Suppose your application has a feedback form, and because it is an AIR application the user can use it whether he has Internet connectivity or not. Imagine that the user is offline and he submits the form. What should the application do? I think one reasonable answer would be to save the data locally and then send it to the server the next time when the application is online. In this situation SQLite could be the local data store.

Below is sample code that let’s you write some data to a table and read the data. Basically when you want to work with SQLite, you need to create a connection (SQLConnection) and open the connection pointing to the file that stores the database. After this, you use a SQLStatement yo create queries and execute them. Thus, you can create tables, insert/update/delete/read data.

//create the database and table
private function createDb():void {
    //create the database file in the application storage folder
    var file:File = File.applicationStorageDirectory.resolvePath("my.db");
    sqlConnectionSync = new SQLConnection();//create a connection object
    sqlConnectionSync.open(file, SQLMode.CREATE);//create the database
    if(file.exists)
        return;
    //create a statement
    var createDb:SQLStatement = new SQLStatement();
    //create a table
    createDb.text = "CREATE TABLE messages (id INTEGER PRIMARY KEY AUTOINCREMENT, subject VARCHAR(64), message VARCHAR(255))";
    createDb.sqlConnection = sqlConnectionSync; //set the connection that will be used
    createDb.execute();//execute the statement
}
//write the data
private function writeData():void {
    var insert:SQLStatement = new SQLStatement(); //create the insert statement
    insert.sqlConnection = sqlConnectionSync; //set the connection
    insert.text = "INSERT INTO messages (subject, message) VALUES (?, ?)";
    insert.parameters[0] = subject.text;
    insert.parameters[1] = message.text;
    insert.execute();
    Alert.show("The data was saved into the table!");
}
//read the data
private function readData():void {
    var read:SQLStatement = new SQLStatement(); //create the read statemen
    read.sqlConnection = sqlConnectionSync; //set the connection
    read.text = "SELECT id, subject, message FROM messages ORDER BY id";
    read.execute();
    var result:SQLResult = read.getResult(); //retrieve the result of the query
    myDatagrid.dataProvider = result.data; //display the array of objects into the data grid
}

This example uses synchronous calls. You can use asynchronous calls. See the documentation for SQLConnection. Also, you can execute the queries in transactions if you want.

Store ActionScript objects in files

You might have objects that you want to save locally and you don’t want to use the SQLite for this. With AIR you can save any ActionScript object to a file. You can save anything from simple objects to arrays of value objects. However there is a catch: when the object you stored has a type (let’s say for example VOPerson), then  when you retrieve it is safe to cast to the original type. But if you save an ArrayCollection of VOPerson, then when you retrieve them you will have an ArrayCollection of Objects. More on this here.

Below is an example of code that writes/reads an Object to and from a file. You use the File class to create a file under the application storage folder, and then you use a FileStream to write the Object to this file. When you read, you use a File to get the file and a FileStream to read the contents of the file.

//write an Object to a file
private function writeObject():void {
    var object:Object = new Object();//create an object to store
    object.value =  asObject.text; //set the text field value to the value property
    //create a file under the application storage folder
    var file:File = File.applicationStorageDirectory.resolvePath("myobject.file");
    if (file.exists)
        file.deleteFile();
    var fileStream:FileStream = new FileStream(); //create a file stream
    fileStream.open(file, FileMode.WRITE);// and open the file for write
    fileStream.writeObject(object);//write the object to the file
    fileStream.close();
}
//read an object stored into a file
private function readObject():void {
    //read the file
    var file:File = File.applicationStorageDirectory.resolvePath("myobject.file");
    if (!file.exists) {
        Alert.show("There is no object saved!");
        return;
    }
    //create a file stream and open it for reading
    var fileStream:FileStream = new FileStream();
    fileStream.open(file, FileMode.READ);
    var object:Object = fileStream.readObject(); //read the object
    Alert.show("The text member has this value: " + object.value);
}

Store assets in files

If you have an AIR application that frequently uses the same pictures, sounds, movies, or other SWF files you might want to save these assets locally, and thus you the overhead of downloading these resources each time. The workflow is almost the same as the previous one for storing ActionScript objects in files. Only this time you don’t write an ActionScript object, you write the bytes to the disk. So instead of fileStream.writeObject(myObject), I use fileStream.writeBytes(bytes, 0, bytes.length). Below is some sample code that asks for a resource URL (such as an JPG file for example) and using an URLLoader, downloads the resource and saves it locally.

<mx:Script>

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

/**
 * This is the click handler for the button that save the web resource locally.
 * Just trigger 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.
    //get the file name of the resource
    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 left="10">    <mx:Label text="Store assets in files" fontSize="20"/>    <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>

You can read more on this here.

Store ActionScript objects in the encrypted local store

Sometimes you have sensitive data, such as personal information or passwords and you want to save them locally. But you don’t want this data to be read by other users or applications. The solution for this problem is to use the encrypted local store. This is a built in functionality in AIR, and each AIR application has its own encrypted local store. Thus you can very safely store any sensitive information you might have. You have access to this store using EncryptedLocalStore object. You have setItem(), getItem() and removeItem() methods. The data saved and read are ByteArray, and when you store or retrieve something you use a key. Below is a code sample:

<mx:Script>
//store the text in the encrypted local store 
private function encrypt():void {
    var data:ByteArray = new ByteArray();
    data.writeUTFBytes(encryptText.text);//create a byte array out of the text we want to encrypt
    EncryptedLocalStore.setItem("myEncryptedData", data); //store the byte array into the encrypted local storage 
}
//read the data from the encrypted local store
private function decrypt():void {
    //using the same key I used when I wrote the data, I reead the bytes back
    var bytes:ByteArray = EncryptedLocalStore.getItem("myEncryptedData");
    if(bytes)
        Alert.show(bytes.readUTFBytes(bytes.bytesAvailable));
    else
        Alert.show("There was no value to be read!");
}
</mx:Script>
<mx:VBox left="10">
    <mx:Label text="Store ActionScript objects in the encrypted local store" fontSize="20"/>
    <mx:TextInput id="encryptText" />
    <mx:Button label="Encrypt" click="encrypt()" />
    <mx:Button label="Decrypt" click="decrypt()" />
</mx:VBox>

You can read more on this subject here.

Final words

You can download the exported project from here. You can import the project in Flex Builder using Import > Flex Builder > Flex Project.

33 thoughts on “Storing data locally in AIR

  1. Pingback: Store data locally in AIR | Adobe AIR Tutorials

  2. @Arun Patel

    Send the data back to server. You can use HTTPService (REST services), RemoteObject, or WebService.

  3. I have already done in HTTP Service,Remote Object and Webservice in Flex.but how it is done in done in AIR Application.

    thanks.

  4. I don’t have one right now. But there is no difference between using this services in Flex web app, or in a Flex AIR app.

    Actually you can use the example from this post, and change only the type of project you create. Instead of Flex with PHP, AIR with PHP. It should work without any changes.

    Good luck!

  5. Hello Mihai !

    Have you had any experience on local caching of encrypted files ? For instance a MP3 file that you want to cache locally, but not allow the user to “steal” the file. Are there methods to encrypt mediafiles and leave them unusable to any other application than the Air app that stored the file ?

    Thanks !

  6. @Nils

    We have solutions for DRM (based on FMS servers). however, you could use for your usecase storing the mp3 files inside of encrypted local database.

    You need to protect only the transfer from server to the client.

  7. hye…i have read your post!!it’s interesting!!i have an example of application to save data into local database.but the example using data input from user(like a form)then save the data to database.i want to ask,what if my application data come from other type of input(user browse a file).how could i save the data to the database??
    could u show me.so that i can learn.thanks a lot!!!

  8. hye…i’m interested in your article.but u didn’t mention on how an application can save data in the database.for example,when user click the ‘save’ button,all the data in that application can be saved into the database.

    can you show that.

  9. @dieyana

    I don’t understand what you mean. The first topic my article is about how to save data in the local SQLite database (function writeData()).

  10. ok…most of the example on local database is about user input data(a form).what if my application doesn’t have a form?it contain a datagrid.i want to save data in the datagrid into local database.can u show me how??i’m desperately need this solution.thanks a lot.

  11. How do I load the swf back into the Air app?
    I tried Swfloader.source = bytearray;
    and Loader.LoadBytes(bytearray)

    but I never get the loader.content object, it’s always null

    I worked many hours on this problem, I need HELP !!

  12. ehm, i should have checked the loader complete event.
    and learn that when I am stepping the complete event does not popup

  13. 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.

  14. Hi Avirag, what are you building?

    I had similar problem, I ended up downloading the files from the Air application and store them in the Storage directory. Only tricky part is how you then get the swf files in the swfloaders, because that’s a securtity issue.

  15. Great article, thanks.
    The app I am designing, requires storing a report generated during a process, in a location of the users choice. Can we use the “store assets in files” to do this?
    For example, after running a particular process, the user needs to store the error or exception report. Thanks in advance.

  16. Correction: by the API docs, EncryptedLocalStore is not secure from other applications ran by the same user account.

  17. @Ain

    This is what API docs says:

    “The Adobe® AIR® runtime provides a persistent encrypted local store (ELS) for each AIR application installed on a user’s computer. This lets you save and retrieve data that is stored on the user’s local hard drive in an encrypted format that cannot easily be deciphered by other users. A separate encrypted local store is used for each AIR application, and each AIR application uses a separate encrypted local store for each user.

    The ELS is appropriate for storing information that must be kept private from other users. It does not, however, protect the data from other processes run under the same user account. It is thus not appropriate for protecting secret application data, such as DRM or encryption keys.”

    http://help.adobe.com/en_US/air/html/dev/WS5b3ccc516d4fbf351e63e3d118666ade46-7e31.html

  18. Pingback: adobe air accessing sql database | Air Data

  19. Hi,

    Is there a way to store data which is available to all users of the machine in Adobe AIR??

  20. Hi,
    I got some performance problem about sqlite in AIR.
    When I have data Replace Into sqlite on mac, it works fine.
    But on Windows, it slow, 9.7 rows per second, 2000 records need 4-5 mins. Can you help? thanks.

  21. Pingback: Flex Mobile Development: storing data locally : Mihai Corlan

  22. Pingback: Flex Mobile Development: storing data locally : Mihai Corlan

  23. Pingback: Flex Air: Read "ActionScript object" from file then cast? | Build Future Repository

  24. Pingback: Flex Air: Read “ActionScript object” from file then cast?

Leave a Reply

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