Saturday, January 12, 2013

Cordova File API , when getDirectory() and DirectoryReader do NOTHING!

Naturally, within a day of my first successes with PhoneGap Build, I am trying some decidedly non-trivial stuff already. I want map tiles off the Internet via HTTP, but I want them cached so the tiles will still transparently be available when I lose connectivity. My plan, is to use Cordova's File storage API.

I almost immediately hit upon an issue:

The getDirectory() method does NOTHING. Neither the success nor failure callback happen. No exception is raised. This happens in the app as it loads, and also in the weinre Console. It doesn't crash the browser, hang the iPad, create a directory, ... Nothing.

Figuring this out wasted 2 hours of my time, and in retrospect the cause seems almost trivial, almost expected, although short of obvious:

File API's getDirectory() method, cannot recursively create directories, creating required parent directories. It returns instantly, but silently fails, without a callback nor an exception.

// the set of callbacks for the two phases: requesting a handle to the filesystem,
// and requesting access to (or creation of) the specified target directory
var getFSsuccess = function(fs) {
    console.debug('Got fshandle');
    FS = fs;
    FS.root.getDirectory(tiledir, {create:true,exclusive:false}, getDIRsuccess, getDIRfail);
var getFSfail = function () {
    throw new Error('Could not open filesystem');
var getDIRsuccess = function (dir) {
    console.debug('Got dirhandle');
    cachedir = dir;
    fileurl  = fs.root.fullPath + '/' + tiledir;
var getDIRfail = function () {
    throw new Error('Could not open directory ' + layerinstance.options.tiledir);

// getFSsuccess will be called,
// will call FS.root.getDirectory with tiles-greeninfo.terrain
// and create the subfolder as expected
var FS, cachedir, fileurl;
var tiledir = "tiles-greeninfo.terrain";
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, getFSsuccess, getFSfail);

// This will not create tiles/ and then tiles/greeninfo.terrain
// as it's a subfolder and getDirectory doesn't do parent creation
// The catch is that it's SILENT failure:
// the getDIRfail callback will never happen, and no exception will be raised
var FS, cachedir, fileurl;
var tiledir = "tiles/greeninfo.terrain";

If you see this blog posting in Google, and it saves you some time, let me know. I'll be glad to know that someone benefited from my wasted evening. :)

No comments:

Post a Comment