File Plugin getFile neither the success callback nor the failure callback get fired

1,203 views
Skip to first unread message

Georgiy Grigoryan

unread,
Feb 26, 2014, 3:59:42 PM2/26/14
to phon...@googlegroups.com
Hello,

I am on cordova 3.3.1-0.1.2. I believe I've got the org.apache.cordova.file plugin installed properly, but I am having trouble with getFile. I have the following code:

function onInitFs (fs)  {
      console.log('Success: fs: ' + fs.name);
      console.log('fs root name: ' + fs.root.name);
      fs.root.getFile("readme.txt", {create: true}, function(fileEntry) { console.log('Success: file' + fileEntry.name);}, function() {console.log('getFile fail')});
       console.log('after getFile call');
}

function testFs()  {
       window.requestFileSystem(window.PERSISTENT, 5*1024*1024 /*5MB*/, onInitFs, function() { console.log('requestFileSystem fail') } );
}

When I call testFs() I get the following output:

Success: fs: persistent
fs root name: /
after getFile call

So I manage to get to the file system, but when I call getFile neither the success callback nor the failure callback get fired. I am confused. I found someone with the same issue posted on SO:


But they weren't clear with how they solved it. Has anyone seen this before?
   

Georgiy Grigoryan

unread,
Feb 26, 2014, 9:32:40 PM2/26/14
to phon...@googlegroups.com
I am trying to debug this sucker. Here is what I have figured out so far with print statements. 

The call to getFile get across to the native side fine. It takes me to in CDVFile.m

- (void)getFile:(CDVInvokedUrlCommand*)command

{

    NSString* baseURIstr = [command.arguments objectAtIndex:0];

    CDVFilesystemURL* baseURI = [CDVFilesystemURL fileSystemURLWithString:baseURIstr];

    NSString* requestedPath = [command.arguments objectAtIndex:1];

    NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil];

    NSLog(@"baseURI %@", baseURIstr); // I ADDED THIS LINE

    NSObject<CDVFileSystem> *fs = [self filesystemForURL:baseURI];

    CDVPluginResult* result = [fs getFileForURL:baseURI requestedPath:requestedPath options:options];


    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];

}

The second line is where I suspect the problem lies. 
[CDVFilesystemURL fileSystemURLWithString:baseURIstr]; returns nil. And I guess it's downhill from there. Not sure why this is happening or if this is indeed the problem. But this is all I came up with so far.


    CDVFilesystemURL* baseURI = [CDVFilesystemURL fileSystemURLWithString:baseURIstr];

Georgiy Grigoryan

unread,
Feb 26, 2014, 9:40:12 PM2/26/14
to phon...@googlegroups.com

This call:

 [CDVFilesystemURL fileSystemURLWithString:baseURIstr];

...leads to this call:

+ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL

{

   return [[CDVFilesystemURL alloc] initWithString:strURL];

}

...leads to this call:

- (id) initWithString:(NSString *)strURL

{

    if ( self = [super init] ) {

        NSURL *decodedURL = [NSURL URLWithString:strURL];

        return [self initWithURL:decodedURL];

    }

    return nil;

}

Which is how I end up with nil for baseURIstr. So it appears [super init] is failing for some reason in initWithString:(NSString *)strURL.


On Wednesday, February 26, 2014 3:59:42 PM UTC-5, Georgiy Grigoryan wrote:

Georgiy Grigoryan

unread,
Feb 26, 2014, 9:57:25 PM2/26/14
to phon...@googlegroups.com
Please disregard my last 3 debudding messages. None of that is happening anymore...

I need to sleep on this... Sorry for the trouble. 

Georgiy Grigoryan

unread,
Feb 27, 2014, 2:40:02 PM2/27/14
to phon...@googlegroups.com
SOLVED!!!

Finally I figured it out. Here is the summary of what was wrong. In my case the problem is specific to iOS, 
but something similar may be happening for other platforms, 
I just don't know because I am only working with iOS at the moment.

I looked at getFile on the native side in CDVFile.m. And after a million NSLog statements I discovered a problem in this line:

        NSObject<CDVFileSystem> *fs = [self filesystemForURL:baseURI];

It always ends up with fs == null.

Tracing all the function calls I ended up in 

- (NSString *)filesystemNameForLocalURI:(NSURL *)uri
{
    NSLog(@"filesystemNameForLocalURI: [uri scheme] %@", [uri scheme]);
    if ([[uri scheme] isEqualToString:kCDVFilesystemURLPrefix] && [[uri host] isEqualToString:@"localhost"]) {
        NSArray *pathComponents = [uri pathComponents];
        if (pathComponents != nil && pathComponents.count > 1) {
            return [pathComponents objectAtIndex:1];
        }
    } else if ([[uri scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
        return @"assets-library";

    }
    return nil;
}

The value of the argument uri was always "/" which was causing the above function to return nil. I went back to getFile in CDVFile.m "did the math" and discovered that
baseURI, which is an argument received from the Javascript side is "/" yet downstream it is expected to conform to a particular scheme as we saw above. So
I started looking on the JS side of the plugin to figure out what is wrong. When I looked here:

https://github.com/apache/cordova-plugin-file/tree/master/www

I noticed that there is a ios directory that contains two files:
FileSystem.js and Entry.js

This is the contents of FileSystem.js inside the ios directory:

FILESYSTEM_PROTOCOL = "cdvfile";

module.exports = {
    __format__: function(fullPath) {
        var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/');
        return FILESYSTEM_PROTOCOL + '://localhost' + path;
    }

This is the code that constructs a "proper" uri, but it did NOT get pulled into my platforms/ios/www/plugins/org.apache.cordova.file.
I assume it was meant to happen automatically, but doesn't or didn't in my case.
When I manually copy the above lines from ios specific
FileSystem.js to my FileSystem.js everything works.
By contrast the iOS specific Entry.js DID get pulled into my platforms/ios/www/plugins/org.apache.cordova.file, so that's fine.

Looking at plugin.xml I noted the following lines:

        <!-- ios specific file apis -->
        <js-module src="www/ios/Entry.js" name="iosEntry">
            <merges target="window.Entry" />
        </js-module>
        <js-module src="www/ios/FileSystem.js" name="iosFileSystem">
            <merges target="window.FileSystem" />
        </js-module>


It looks like plugin.xml is setup correctly, so perhaps that problem is with iOS specific FileSystem.js? I am not sure why it's not getting pulled in automatically,
but I just tried it on fresh project by running:

cordova plugin add https://github.com/apache/cordova-plugin-file

cordova prepare

 And it's still the same issue.

I am still not totally sure if it was my mistake somehow or if this is a bug in the plugin, but I wanted to post this here for everyone's benefit.

Georgiy Grigoryan

unread,
Feb 27, 2014, 4:34:18 PM2/27/14
to phon...@googlegroups.com
Small correction:

Rather than copy these line exactly like this:

FILESYSTEM_PROTOCOL = "cdvfile";

module.exports = {
    __format__: function(fullPath) {
        var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/');
        return FILESYSTEM_PROTOCOL + '://localhost' + path;
    }

You have to "extract the __format__ function, so that your final FinalSystem.js looks like this:

cordova.define("org.apache.cordova.file.FileSystem", function(require, exports, module) { /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ var DirectoryEntry = require('./DirectoryEntry'); /** * An interface representing a file system * * @constructor * {DOMString} name the unique name of the file system (readonly) * {DirectoryEntry} root directory of the file system (readonly) */ var FileSystem = function(name, root) { this.name = name || null; if (root) { this.root = new DirectoryEntry(root.name, root.fullPath, this); } else { this.root = new DirectoryEntry(this.name, '/', this); } }; FileSystem.prototype.__format__ = function(fullPath) { return fullPath; }; FILESYSTEM_PROTOCOL = "cdvfile"; FileSystem.prototype.__format__ = function(fullPath) { var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/'); return FILESYSTEM_PROTOCOL + '://localhost' + path; }; module.exports = FileSystem; });

 

Olivier Ziadé

unread,
Mar 11, 2014, 9:38:13 AM3/11/14
to phon...@googlegroups.com
Hello ! 

I've got the same issue. Thanx a lot for the fix, it works for me.
I can't see why it does not work without this fix. In my platform/ios/www/plugins/org.apache.cordova.file/www/ios, i have the two specific files Entry.js and FileSystem.js. It seems that they are not included somewhere.




--
-- You received this message because you are subscribed to the Google
Groups "phonegap" group.
To post to this group, send email to phon...@googlegroups.com
To unsubscribe from this group, send email to
phonegap+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/phonegap?hl=en?hl=en
 
For more info on PhoneGap or to download the code go to www.phonegap.com
 
To compile in the cloud, check out build.phonegap.com
---
You received this message because you are subscribed to the Google Groups "phonegap" group.
To unsubscribe from this group and stop receiving emails from it, send an email to phonegap+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Sudam Swain

unread,
Apr 4, 2014, 1:54:13 AM4/4/14
to phon...@googlegroups.com
Hi I got same issue. But can not solved .I did what you replied. But 
fileSystem.root.getFile is not working . can u help me to solve. 

Rob Bramhall

unread,
Jan 15, 2015, 2:42:40 PM1/15/15
to phon...@googlegroups.com
I tried this and variations, and none of them work. They all actually make it worse were the fs.root.createReader no longer works. 

I am assuming is to update the contents of the /plugins/org.apache.cordova.file/www/ios/FileSystem.js contents.

But it has just: 
FILESYSTEM_PROTOCOL = "cdvfile";

module.exports = {
    __format__: function(fullPath) {
        var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/');
        return FILESYSTEM_PROTOCOL + '://localhost' + path;
    }

and thus replacing that with this breaks it:

var DirectoryEntry = require('./DirectoryEntry'); /** * An interface representing a file system * * @constructor * {DOMString} name the unique name of the file system (readonly) * {DirectoryEntry} root directory of the file system (readonly) */ var FileSystem = function(name, root) { this.name = name || null; if (root) { this.root = new DirectoryEntry(root.name, root.fullPath, this); } else { this.root = new DirectoryEntry(this.name, '/', this); } }; FileSystem.prototype.__format__ = function(fullPath) { return fullPath; }; FILESYSTEM_PROTOCOL = "cdvfile"; FileSystem.prototype.__format__ = function(fullPath) { var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/'); return FILESYSTEM_PROTOCOL + '://localhost' + path; }; module.exports = FileSystem;




Rob Bramhall

unread,
Jan 15, 2015, 3:17:31 PM1/15/15
to phon...@googlegroups.com
Now this is really weird. 

After trying everything and rolling all of the code back (undoing), saving, then "cordova build", then xcode Run..... It is working....

Huh???? So it hasn't been working for days and then in essence, simply touching the plugin file, it is working? 

Weird. But moving forward, the getFile is working!

Rob
Reply all
Reply to author
Forward
0 new messages