11

Using Cordova/PhoneGap 3.3.0, I am downloading a file using the FileTransfer plugin, and then trying to open it using the InAppBrowser plugin. I can download the file successfully, and place it in the temp directory. Since the File plugin now uses URL schema, I cannot figure out how to pass the correct url/path to the window.open method of the InAppBrowser plugin. I cannot find any relevant documentation either. All of the "download and open" documentation I can find is out of date and pre-URL-schema.

Relevant links:

Out of date examples I found:

Here is my code:

var uri = encodeURI("http://some.url/file.pdf");
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0,
    function (fileSystem) {
        var fileTransfer = new FileTransfer();
        var filename = fileSystem.root.toURL() + uri.substr(uri.lastIndexOf("/") + 1);
        fileTransfer.download(uri, filename,
            function(entry) { // download success
                var path = entry.toURL(); //**THIS IS WHAT I NEED**
                window.open(path, "_system");
            },
            function(error) {} // irrelevant download error
        );
    },
    function(error) {} // irrelevant request fileSystem error
);

I am currently testing in Android on a Nexus 7 and Nexus 5. The InAppBrowser correctly opens the default pdf launcher (in my case Adobe Reader), but then I get a "The document path is not valid" error.

[Update: showing return values]

I have tried all of the following combinations for the file path:

var path = entry.toURL(); // "cdvfile://localhost/temporary/file.pdf"
var path = entry.fullPath; // "file.pdf"
var path = fileSystem.root.toURL() + filename; // "cdvfile://localhost/temporary/file.pdf"
var path = fileSystem.root.fullPath + filename; // "/file.pdf"
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Soturi
  • 1,486
  • 1
  • 14
  • 30
  • if you updated the plugins recently, maybe you have to deal with new URL scheme `cdvfile://`? http://cordova.apache.org/news/2014/02/10/plugins-release.html – QuickFix Feb 21 '14 at 18:12
  • Thanks for comment. I am using these latest plugins, referenced in your provided link. I read this, but couldn't remember the URL for my posting. I added it to the relevant links section. When I call `entry.toURL()` I am getting links with the `cdvfile://` prefix – Soturi Feb 21 '14 at 18:43
  • stupid question: why don't you use the original url directly with window.open instead of first downloading it? – QuickFix Feb 21 '14 at 21:47
  • It's not a stupid question. I was doing that previously, but some Android devices display "Cannot open file." error. It is the oddest thing. Using that method, the file downloads correctly, and I can open in Adobe through a file explorer, but when opening through Downloads app, the error is displayed. I thought this was a MIME type issue, but I confirmed that the correct MIME type was being used. Besides, opening it through the app saves the user an extra step of having to click the downloaded file to open it (assuming it worked correctly anyways). – Soturi Feb 24 '14 at 12:52
  • 1
    maybe try to use the webintent plugin instead of inappbrowser to open the pdf : https://github.com/Initsogar/cordova-webintent – QuickFix Feb 24 '14 at 13:13
  • Just installed and used the plugin, and it worked! I had to use the absolute path, but as long as it works I am happy. If you re-post as an answer, I will mark it as the solution. Thank you so much for your time! – Soturi Feb 24 '14 at 13:34

7 Answers7

6

Since Cordova 3.4 the file protocol has changed and instead of using fullPath they now provide the toURL() that returns a cdvfile://path/to/your/file.ext path.

So when you download a file using the filesystem object's callback (with the entry argument) just call the entry.toURL() and open this using the following statement to open it - assuming you have InApBrowser installed and the _blank will open the InAppBrowser's window:

window.open(entry.toURL(), '_blank', 'location=no,closebuttoncaption=Close,enableViewportScale=yes');  

I wrote about it in this post on my blog (if you want all the references and background info).

EeKay
  • 6,494
  • 3
  • 24
  • 24
5

I THINK I have a solution to this, but it's kinda nasty.

I grepped through the cordova JAVA and looked for places it constructed a file entry JSON object. Specifically by looking for places where its adding fullPath to the object.

I added an additional entry for "fullAbsolutePath" with the value [file].getAbsolutePath(), where [file] is whatever java.io.file instance is nearby. I did this in all the places I could find just to be safe and because it doesn't seem to hurt anything.

Then I modified FileEntry.js and File.js in the plugins\file folder to also populate that value to the file entry object.

Still trying to work out the kinks, but I believe I'm on the right track...

I think a better solution would be to modify the inAppBrowser plugin to recognize and resolve the cordovaFile:// protocol and im sure they obscured the absolute file system path on purpose - but that might be a bit beyond me.

EDIT - Yup! this works! I can now take a file entry, call the file method, then read fullSystemPath off the fileObject. Value is like "/storage/emulated/0/whatever/" on my android. Just need to prepend "file://" and window.open will accept it.

cor
  • 3,323
  • 25
  • 46
nihlton
  • 659
  • 6
  • 7
  • 2
    Thanks for all that work. I looked at the cordova.java as well to see where you might have put all those references to `fullAbsolutePath`. You might want to submit that to the cordova team for the fileentry or inappbrowser plugins. Can't believe they didn't include that in the updated releases. I agree though, that it might make more sense to edit inappbrowser to recognize the url correctly. Glad you got it to work though! – Soturi Mar 10 '14 at 18:51
  • heh no worries. I was actually trying to solve the same problem for myself, and figured i'd share. – nihlton Mar 26 '14 at 20:35
  • @nihlton how would you get a file to save to your app folder? – trainoasis Jun 19 '14 at 11:50
2

In the latest cordova docs they say

If you are upgrading to a new (1.0.0 or newer) version of File, and you have previously been using entry.fullPath as arguments to download() or upload(), then you will need to change your code to use filesystem URLs instead.

FileEntry.toURL() and DirectoryEntry.toURL() return a filesystem URL of the form

cdvfile://localhost/persistent/path/to/file which can be used in place of the absolute file path in both download() and upload() methods.

What you can try is remove cdvfile://localhost/persistent to have a url that would work with your window.open. (maybe start with a alert or console.log of what you get with entry.toURL())

QuickFix
  • 11,661
  • 2
  • 38
  • 50
  • Thanks for this. I found this documentation as well, but lost the URL for it. I have tried using `toURL()`, which also does not return a url that works. I just edited my posting above to show return values. Removing "cdvfile://localhost/temporary" gives me the same result as `entry.fullPath` which also doesn't work. – Soturi Feb 21 '14 at 18:47
  • Maybe try with 'file:///sdcard/'+entry.fullPath; – QuickFix Feb 21 '14 at 20:58
  • I tried using the absolute path as well, but was unsuccessful with inappbrowser. However, using the plugin in your previous suggestion I had success! – Soturi Feb 24 '14 at 13:33
1

In current plugin dev branch there is a solution:

Entry.toNativeURL() - Returns the full path to the file in the device FileSystem.

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

xudre
  • 2,731
  • 2
  • 19
  • 19
1

I know this is answered already, but I had the most success with entry.toInternalURL().

keldar
  • 6,152
  • 10
  • 52
  • 82
0

The path that follow to "cdvfile://localhost/persistent" is like a root app (www folder) path. In other words, I mean you have access to the images or downloaded files using the path that follow "cdvfile://localhost/persistent".

Example

Download target Path: "cdvfile://localhost/persistent/MyImages/thebestimageever.jpg"

In a HTML image tag I could do this: <img src="/MyImages/thebestimageever.jpg" />

And it works well.

Rahnzo
  • 737
  • 2
  • 7
  • 20
0

Just write the window.open within the download method or ask for file system and entry again before opening if you want to make it separately

function downloadFile(fileURL, destination, fileName) {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
    fileSystem.root.getDirectory(destination, {
        create: true
    }, function (dirEntry) {
        var ft = new FileTransfer();
        ft.download(fileURL, dirEntry.toURL() + "/fileName", function (entry) {
            alert(fileName + " downloaded successfully at:" + dirEntry.fullPath);
            window.open(dirEntry.toURL() + "fileName", "_blank", "location=yes");
        }, function (error) {
            alert("download failed: " + JSON.stringify(error));
        });
    }, function (error) {
        alert("dir creation failed: " + JSON.stringify(error));
    });
}, function (error) {
    alert("requesting file system failed: " + JSON.stringify(error));
});

}

if your destination is more than one folder level then you have to ask for getDirectory recursively one by one (if your folders are already created then one call of the method is enough)

PS: - on iOS files are downloaded to 'Documents' folder and not to 'www' so not the same location of your app.js content as some people say - if you are opening a html page with js and css from a downloaded unzipped folder then you have to make some changes on InAppBrowser.m to make it load properly

Chepaki
  • 16
  • 3