Free Trial
|

PhoneGap: Storing and Retrieving with the FileSystem

PhoneGap, also known as Apache Cordova, is a framework for building mobile apps using HTML, JavaScript and CSS. It allows web developers to leverage their existing skills in the exciting world of mobile development.

PhoneGap provides an execution environment for your front-end code with a number of native device APIs exposed: the device’s sensors (GPS, accelerometer, and compass), for instance, or the user’s contacts. Using the JavaScript APIs provided, developers can quickly build native-style mobile experiences ready for mobile devices on, at last count, eight different platforms.

One important set of APIs are those for accessing the device filesystem. While many mobile browsers provide APIs for variously structured local storage – the webSQL SQLite interface, or the window.localStorage object – the standards-track File APIs are yet to be implemented widely, especially on mobile.

PhoneGap gives us a version of these APIs tracking the latest specs. For this article, we’ll be looking at the APIs as exposed in PhoneGap 1.4.1.

Accessing The FileSystem

We’re going to write a simple (and, alas, ugly) app for storing contacts – no personal data, just names and our descriptions of the names.

Let’s start with some simple markup for our app:

<body>
    <form onsubmit="return saveText()" action="#">
        <label for="name">Name</label><br>
        <input id="name" /><br>

        <label for="desc">Description</label><br>
        <input id="desc" /><br>

        <input type="submit" value="Save" />
    </form>

    <dl id="definitions">
    </dl>
</body>

Now let’s add some JavaScript at the bottom: the code to include PhoneGap and some objects and functions we’ll use later.

<script src="phonegap.js"></script>
<script>
    var FILENAME = 'database.db',
        $ = function (id) {
            return document.getElementById(id);
        },
        file = {
            writer: { available: false },
            reader: { available: false }
        },
        dbEntries = [];

    function saveText() {
        // placeholder for when the text gets saved
        return false;
    }
</script>

To access the filesystem, we’ll need to call window.requestFileSystem – a W3C specified API that PhoneGap has implemented. To do so, we need to be aware of a couple of things:

  1. PhoneGap APIs are only available after the deviceready event has fired on the document.
  2. You should pass a success and an error callback to each asynchronous function.

Here’s what we’ll add to our second script tag:

var failCB = function (msg) {
    return function () {
        alert('[FAIL] ' + msg);
    }
};

function gotFS(fs) {
    // placeholder success callback
}

document.addEventListener('deviceready', function () {
    var fail = failCB('requestFileSystem');
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}, false);

Here is what’s happening:

Now let’s add the various callbacks to get a handle on a particular entry, first modifying the gotFS function we had defined:

function gotFS(fs) {
    var fail = failCB('getFile');
    fs.root.getFile(FILENAME, {create: true, exclusive: false},
                    gotFileEntry, fail);
}

function gotFileEntry(fileEntry) {
    file.entry = fileEntry;
}

We need an extra asynchronous call to get the file entry. Now that we have it, we can create a writer and/or a reader to modify what’s in the file.

Writing Text Out

If you want to write a file, you first need to create a FileWriter object. As you may have guessed, this is another asynchronous action; let’s modify gotFileEntry to make the call, and create a callback function:

function gotFileEntry(fileEntry) {
    var fail = failCB('createWriter');
    file.entry = fileEntry;

    fileEntry.createWriter(gotFileWriter, fail);
}

function gotFileWriter(fileWriter) {
    file.writer.available = true;
    file.writer.object = fileWriter;
}

Now that we have the FileWriter available, we can modify the saveText function to do something with it:

function saveText(e) {
    var name = $('name').value,
        desc = $('desc').value,
        fail;

    dbEntries.push('' + name + '' + desc + '</dd>') $('name').value = ''; $('desc').value = ''; $('definitions').innerHTML = dbEntries.join(''); if (file.writer.available) { file.writer.available = false; file.writer.object.onwriteend = function (evt) { file.writer.available = true; file.writer.object.seek(0); } file.writer.object.write(dbEntries.join("n")); } return false; }

Here is a quick review of what’s going on here:

This gets the basic functionality we’re after; unfortunately, the database.db file will be overwritten every time the app gets launched. To fix this, you’ll want to use the FileReader object.

Reading Text Back

You may have guessed where we’re going here:

  1. We need to (asynchronously) create a FileReader object.
  2. We’re then going to (asynchronously) read a file.

Frustratingly, the FileReader is created by itself and passed a FileEntry object, as opposed to the FileWriter which is created by a method on the FileEntry. Hopefully these inconsistencies will be settled by the time the W3C standardizes on something.

Anyhow, let’s write a quick function to populate our definitions list from the database.db as we’ve constructed it.

function readText() {
    if (file.entry) {
        file.entry.file(function (dbFile) {
            var reader = new FileReader();
            reader.onloadend = function (evt) {
                var textArray = evt.target.result.split("n");

                dbEntries = textArray.concat(dbEntries);

                $('definitions').innerHTML = dbEntries.join('');
            }
            reader.readAsText(dbFile);
        }, failCB("FileReader"));
    }
}

And finally, let’s ensure that it gets called when the file system is ready by modifying the gotFileEntry method:

function gotFileEntry(fileEntry) {
    var fail = failCB('createWriter');
    file.entry = fileEntry;

    fileEntry.createWriter(gotFileWriter, fail);
    readText();
}

To make sure everything’s working:

You can see the full source code of our app here.

Summary

This fairly contrived example shows the basics of how to get started using the File APIs as they’re implemented in PhoneGap 1.4.1. For a simple use case like this, you may want to use one of the HTML5 APIs for structured data, such as the WebSQL database or the window.localStorage interface. The PhoneGap File APIs can really shine when you need to do more complex interactions with the FileSystem (seeking within, truncating, appending to files, and so forth), and exporting those files out of the app and onto a remote server.

Hopefully this tutorial has covered the basics well enough that you can easily get started playing with these APIs on your own apps.

Safari Books Online has the content you need

Check out these Phonegap books available from Safari Books Online. If you don’t have a subscription to Safari Books Online, you can start with a free 10-day trial.

PhoneGap Beginner’s Guide, written by Andrew Lunny, the author of this post, will show you how to use the PhoneGap mobile development framework to target multiple mobile platforms: iOS, Android, BlackBerry, and more with a single application. With PhoneGap, you can use existing web development skills, instead of learning a new environment for every platform on the market.
Using HTML, CSS, and Javascript, PhoneGap allows you to jump into the mobile world and develop apps for iPhone, Android, and the BlackBerry, and Beginning PhoneGap will help show you how to best take advantage of PhoneGap.
Beginning PhoneGap: Mobile Web Framework for JavaScript and HTML5 is a definitive, one-of-a-kind book that teaches the fundamentals and strategies behind cross-platform mobile application development. Instead of learning languages like Objective-C, focus on building apps from day one for Android, iOS, Blackberry, WebOS and Symbian—without the complexities of these platforms.
Head First Mobile Web shows how to use the web tech- nology you’re already familiar with to make sites and apps that work on any device of any size. Put your JavaScript, CSS media query, and HTML5 skills to work, and then optimize your site to perform its best in the demanding mobile market.
Build Mobile Websites and Apps for Smart Devices provides practical, up to date information on all aspects of Mobile Web Development, using an easy to follow, tutorial style, with step-by-step instructions and clear examples.

Start FREE 10-day trial.

About the Author

  Andrew Lunny is a software developer based in San Francisco, and the author of PhoneGap: Beginner’s Guide, from Packt Publishing. He currently works at Adobe on the PhoneGap Build project, building thousands of apps a day for five different mobile platforms. He is also responsible for writing cogent error messages when something inevitably goes wrong. You can follow him on Twitter at @alunny.
|

3 Responses to PhoneGap: Storing and Retrieving with the FileSystem

  1. Pingback: PhoneGap Tip: Binary FileSystem Data « Safari Books Online's Official Blog

  2. Pingback: PhoneGap Tip: Uploading Files « Safari Books Online's Official Blog

  3. ash@mwsys.com.au says:

    What is the main difference between the file system and the webSQL? Will both databases hold data when the phone is turned off or the app is closed?

Facebook Twitter RSS feed